From 03c6de97f6fd5b1683863d7243b1f6ee47bfaa80 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:35:18 +0200 Subject: [PATCH 01/11] dts: bflb: Add bl70x dts Introduce most basic DTS for BL70x Signed-off-by: Camille BAUD --- dts/riscv/bflb/bl702.dtsi | 8 ++++ dts/riscv/bflb/bl704.dtsi | 8 ++++ dts/riscv/bflb/bl706.dtsi | 8 ++++ dts/riscv/bflb/bl70x.dtsi | 97 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 dts/riscv/bflb/bl702.dtsi create mode 100644 dts/riscv/bflb/bl704.dtsi create mode 100644 dts/riscv/bflb/bl706.dtsi create mode 100644 dts/riscv/bflb/bl70x.dtsi diff --git a/dts/riscv/bflb/bl702.dtsi b/dts/riscv/bflb/bl702.dtsi new file mode 100644 index 0000000000000..0143593fb1fb4 --- /dev/null +++ b/dts/riscv/bflb/bl702.dtsi @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/bflb/bl704.dtsi b/dts/riscv/bflb/bl704.dtsi new file mode 100644 index 0000000000000..231bb24b5465d --- /dev/null +++ b/dts/riscv/bflb/bl704.dtsi @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/bflb/bl706.dtsi b/dts/riscv/bflb/bl706.dtsi new file mode 100644 index 0000000000000..56f92e72beb63 --- /dev/null +++ b/dts/riscv/bflb/bl706.dtsi @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/bflb/bl70x.dtsi b/dts/riscv/bflb/bl70x.dtsi new file mode 100644 index 0000000000000..5ab285b8b46bb --- /dev/null +++ b/dts/riscv/bflb/bl70x.dtsi @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = ; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "sifive,e24", "riscv"; + reg = <0>; + riscv,isa = "rv32imafcb"; + hardware-exec-breakpoint-count = <4>; + status = "okay"; + + ictrl: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + clic: clic@2000000 { + compatible = "sifive,clic-draft"; + reg = <0x2000000 0x10000>; + #address-cells = <0>; + #interrupt-cells = <2>; + + interrupt-controller; + interrupts-extended = <&ictrl 3 &ictrl 7 &ictrl 11 &ictrl 12>; + interrupt-names = "msip", /* Machine Software Interrupt */ + "mtip", /* Machine Timer interrupt */ + "meip", /* Machine External Interrupt */ + "csip"; /* CLIC Software Interrupt */ + }; + + mtimer: timer@200bff8 { + compatible = "riscv,machine-timer"; + reg = <0x200bff8 0x8 0x2004000 0x8>; + reg-names = "mtime", "mtimecmp"; + + interrupts-extended = <&ictrl 7>; + }; + + itcm: itcm@22014000 { + compatible = "zephyr,memory-region", "sifive,dtim0"; + reg = <0x22014000 DT_SIZE_K(12)>; + zephyr,memory-region = "ITCM"; + }; + + flashctrl: flash-controller@4000b000 { + compatible = "bflb,flash-controller"; + reg = <0x4000b000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + interrupts = <39 0>; + interrupt-parent = <&clic>; + }; + + retram: memory@40010000 { + compatible = "mmio-sram"; + reg = <0x40010000 DT_SIZE_K(4)>; + }; + + dtcm: dtcm@42017000 { + compatible = "zephyr,memory-region", "sifive,dtim0"; + reg = <0x42017000 DT_SIZE_K(4)>; + zephyr,memory-region = "DTCM"; + }; + + sram0: memory@42018000 { + compatible = "mmio-sram"; + reg = <0x42018000 DT_SIZE_K(96)>; + }; + }; +}; From ef90e8484e7006095b34db91b4a9cc499979233f Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:37:50 +0200 Subject: [PATCH 02/11] soc: bflb: Add support for BL70x SoCs Adds SoC folder contents for BL70x Signed-off-by: Camille BAUD --- soc/bflb/bl70x/CMakeLists.txt | 15 ++++++ soc/bflb/bl70x/Kconfig | 29 +++++++++++ soc/bflb/bl70x/Kconfig.defconfig | 21 ++++++++ soc/bflb/bl70x/Kconfig.soc | 44 ++++++++++++++++ soc/bflb/bl70x/soc.c | 87 ++++++++++++++++++++++++++++++++ soc/bflb/bl70x/soc.h | 26 ++++++++++ soc/bflb/common/CMakeLists.txt | 2 +- soc/bflb/soc.yml | 8 +++ 8 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 soc/bflb/bl70x/CMakeLists.txt create mode 100644 soc/bflb/bl70x/Kconfig create mode 100644 soc/bflb/bl70x/Kconfig.defconfig create mode 100644 soc/bflb/bl70x/Kconfig.soc create mode 100644 soc/bflb/bl70x/soc.c create mode 100644 soc/bflb/bl70x/soc.h diff --git a/soc/bflb/bl70x/CMakeLists.txt b/soc/bflb/bl70x/CMakeLists.txt new file mode 100644 index 0000000000000..30d065c45279b --- /dev/null +++ b/soc/bflb/bl70x/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") + +zephyr_code_relocate_ifdef(CONFIG_UART_BFLB LIBRARY drivers__serial LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_RISCV_MACHINE_TIMER LIBRARY drivers__timer LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_PINCTRL_BFLB LIBRARY drivers__pinctrl LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_SYSCON_BFLB_EFUSE LIBRARY drivers__syscon LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL70X + LIBRARY drivers__clock_control LOCATION ITCM NOKEEP) diff --git a/soc/bflb/bl70x/Kconfig b/soc/bflb/bl70x/Kconfig new file mode 100644 index 0000000000000..3c191612cceb8 --- /dev/null +++ b/soc/bflb/bl70x/Kconfig @@ -0,0 +1,29 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL70X + select ATOMIC_OPERATIONS_C + select CLOCK_CONTROL + select CODE_DATA_RELOCATION + select CPU_HAS_FPU + select FLOAT_HARD + select FPU + select GEN_IRQ_VECTOR_TABLE + select INCLUDE_RESET_VECTOR + select RISCV + select RISCV_HAS_CLIC + select RISCV_MACHINE_TIMER + select RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING + select RISCV_PRIVILEGED + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_F + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_VECTORED_MODE + select SOC_EARLY_INIT_HOOK + select SYSCON + select XIP diff --git a/soc/bflb/bl70x/Kconfig.defconfig b/soc/bflb/bl70x/Kconfig.defconfig new file mode 100644 index 0000000000000..c883c47d22bfe --- /dev/null +++ b/soc/bflb/bl70x/Kconfig.defconfig @@ -0,0 +1,21 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_BL70X + +# On BL702, BL704 and BL706, not all values work, here is a list of some that work: +# 2000, 1000, 100, 10, 1 +config SYS_CLOCK_TICKS_PER_SEC + default 2000 + +config NUM_IRQS + default 80 + +config ARCH_SW_ISR_TABLE_ALIGN + default 64 + +config RISCV_MCAUSE_EXCEPTION_MASK + default 0x3FF + +endif # SOC_SERIES_BL70X diff --git a/soc/bflb/bl70x/Kconfig.soc b/soc/bflb/bl70x/Kconfig.soc new file mode 100644 index 0000000000000..dcf31b8be2b55 --- /dev/null +++ b/soc/bflb/bl70x/Kconfig.soc @@ -0,0 +1,44 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL70X + bool + select SOC_FAMILY_BFLB + help + Enable support for BouffaloLab BL6xx MCU series + +config SOC_SERIES + default "bl70x" if SOC_SERIES_BL70X + +config SOC_BL702SA0Q2I + bool + select SOC_SERIES_BL70X + +config SOC_BL702S10Q2I + bool + select SOC_SERIES_BL70X + +config SOC_BL702C10Q2H + bool + select SOC_SERIES_BL70X + +config SOC_BL706C10Q2I + bool + select SOC_SERIES_BL70X + +config SOC_BL706S10Q2I + bool + select SOC_SERIES_BL70X + +config SOC_BL706C22Q2I + bool + select SOC_SERIES_BL70X + +config SOC + default "bl702sa0q2i" if SOC_BL702SA0Q2I + default "bl702s10q2i" if SOC_BL702S10Q2I + default "bl702c10q2h" if SOC_BL702C10Q2H + default "bl706c10q2i" if SOC_BL706C10Q2I + default "bl706s10q2i" if SOC_BL706S10Q2I + default "bl706c22q2i" if SOC_BL706C22Q2I diff --git a/soc/bflb/bl70x/soc.c b/soc/bflb/bl70x/soc.c new file mode 100644 index 0000000000000..21756116406f2 --- /dev/null +++ b/soc/bflb/bl70x/soc.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Bouffalo Lab RISC-V MCU series initialization code + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Set Embedded Flash Pullup */ +static void system_bor_init(void) +{ + uint32_t tmp; + + tmp = sys_read32(HBN_BASE + HBN_MISC_OFFSET); + /* borThreshold = 1 */ + tmp = (tmp & HBN_BOR_VTH_UMSK) | ((uint32_t)(1) << HBN_BOR_VTH_POS); + /* enablePorInBor true*/ + tmp = (tmp & HBN_BOR_SEL_UMSK) | ((uint32_t)(1) << HBN_BOR_SEL_POS); + /* enableBor true*/ + tmp = (tmp & HBN_PU_BOR_UMSK) | ((uint32_t)(1) << HBN_PU_BOR_POS); + sys_write32(tmp, HBN_BASE + HBN_MISC_OFFSET); + + + /* enableBorInt false */ + tmp = sys_read32(HBN_BASE + HBN_IRQ_MODE_OFFSET); + tmp = tmp & HBN_IRQ_BOR_EN_UMSK; + sys_write32(tmp, HBN_BASE + HBN_IRQ_MODE_OFFSET); +} + +void soc_early_init_hook(void) +{ + uint32_t key; + uint32_t *p; + uint32_t i = 0; + uint32_t tmp; + + key = irq_lock(); + + + /* disable hardware_pullup_pull_down (reg_en_hw_pu_pd = 0) */ + tmp = sys_read32(HBN_BASE + HBN_IRQ_MODE_OFFSET); + /* "BL_CLR_REG_BIT" */ + tmp = tmp & HBN_REG_EN_HW_PU_PD_UMSK; + sys_write32(tmp, HBN_BASE + HBN_IRQ_MODE_OFFSET); + + /* 'seam' 0kb, undocumented */ + tmp = sys_read32(GLB_BASE + GLB_SEAM_MISC_OFFSET); + tmp = (tmp & GLB_EM_SEL_UMSK) | (0U << GLB_EM_SEL_POS); + sys_write32(tmp, GLB_BASE + GLB_SEAM_MISC_OFFSET); + + /* Reset UART signal swap */ + tmp = sys_read32(GLB_BASE + GLB_PARM_OFFSET); + tmp = (tmp & GLB_UART_SWAP_SET_UMSK) | (0U << GLB_UART_SWAP_SET_POS); + sys_write32(tmp, GLB_BASE + GLB_PARM_OFFSET); + + /* CLear all interrupt */ + p = (uint32_t *)(CLIC_HART0_ADDR + CLIC_INTIE); + + for (i = 0; i < (IRQn_LAST + 3) / 4; i++) { + p[i] = 0; + } + + p = (uint32_t *)(CLIC_HART0_ADDR + CLIC_INTIP); + + for (i = 0; i < (IRQn_LAST + 3) / 4; i++) { + p[i] = 0; + } + + /* init bor for all platform */ + system_bor_init(); + + irq_unlock(key); +} diff --git a/soc/bflb/bl70x/soc.h b/soc/bflb/bl70x/soc.h new file mode 100644 index 0000000000000..19cb5f75ea9d7 --- /dev/null +++ b/soc/bflb/bl70x/soc.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021-2025 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Board configuration macros + * + * This header file is used to specify and describe board-level aspects + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +#include + +#ifndef _ASMLANGUAGE + +/* Add include for DTS generated information */ +#include + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC__H_ */ diff --git a/soc/bflb/common/CMakeLists.txt b/soc/bflb/common/CMakeLists.txt index 17c2403f61898..162490a3eede7 100644 --- a/soc/bflb/common/CMakeLists.txt +++ b/soc/bflb/common/CMakeLists.txt @@ -4,7 +4,7 @@ zephyr_include_directories(.) -if(CONFIG_SOC_SERIES_BL60X) +if(CONFIG_SOC_SERIES_BL60X OR CONFIG_SOC_SERIES_BL70X) zephyr_include_directories(e24) zephyr_sources( e24/soc_irq_privileged.c diff --git a/soc/bflb/soc.yml b/soc/bflb/soc.yml index 1be1f88d5c738..91e585bdac752 100644 --- a/soc/bflb/soc.yml +++ b/soc/bflb/soc.yml @@ -17,4 +17,12 @@ family: - name: bl618m05q2i - name: bl618m50q2i - name: bl618m65q2i + - name: bl70x + socs: + - name: bl702sa0q2i + - name: bl702s10q2i + - name: bl702c10q2h + - name: bl706c10q2i + - name: bl706s10q2i + - name: bl706c22q2i vendor: bflb From 01e1aee62ac23dd7de1d1c9d57131771b110ea74 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:59:25 +0200 Subject: [PATCH 03/11] dts: syscon: Add BL70x efuse node Adds the syscon node Signed-off-by: Camille BAUD --- dts/riscv/bflb/bl70x.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/riscv/bflb/bl70x.dtsi b/dts/riscv/bflb/bl70x.dtsi index 5ab285b8b46bb..2a3164ebd5bf6 100644 --- a/dts/riscv/bflb/bl70x.dtsi +++ b/dts/riscv/bflb/bl70x.dtsi @@ -67,6 +67,13 @@ zephyr,memory-region = "ITCM"; }; + efuse: efuse@40007000 { + compatible = "bflb,efuse"; + reg = <0x40007000 0x1000>; + status = "okay"; + size = <128>; + }; + flashctrl: flash-controller@4000b000 { compatible = "bflb,flash-controller"; reg = <0x4000b000 0x1000>; From 5389146b11b45a7c01ccf07caad378072cfa9a91 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:38:27 +0200 Subject: [PATCH 04/11] drivers: syscon: Add condition for BL70x BL70x = BL60x in this case Signed-off-by: Camille BAUD --- drivers/syscon/syscon_bflb_efuse.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/syscon/syscon_bflb_efuse.c b/drivers/syscon/syscon_bflb_efuse.c index a0fa868b83d76..e8d368dbef514 100644 --- a/drivers/syscon/syscon_bflb_efuse.c +++ b/drivers/syscon/syscon_bflb_efuse.c @@ -73,7 +73,7 @@ static void efuse_bflb_efuse_read(const struct device *dev) tmp = EF_CTRL_EFUSE_CTRL_PROTECT | (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) -#if defined(CONFIG_SOC_SERIES_BL60X) +#if defined(CONFIG_SOC_SERIES_BL60X) || defined(CONFIG_SOC_SERIES_BL70X) | (EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) #endif | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) @@ -95,7 +95,7 @@ static void efuse_bflb_efuse_read(const struct device *dev) tmp = EF_CTRL_EFUSE_CTRL_PROTECT | (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) -#if defined(CONFIG_SOC_SERIES_BL60X) +#if defined(CONFIG_SOC_SERIES_BL60X) || defined(CONFIG_SOC_SERIES_BL70X) | (EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) #endif | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) @@ -109,7 +109,7 @@ static void efuse_bflb_efuse_read(const struct device *dev) tmp = EF_CTRL_EFUSE_CTRL_PROTECT | (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) -#if defined(CONFIG_SOC_SERIES_BL60X) +#if defined(CONFIG_SOC_SERIES_BL60X) || defined(CONFIG_SOC_SERIES_BL70X) | (EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) #endif | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) @@ -131,7 +131,7 @@ static void efuse_bflb_efuse_read(const struct device *dev) tmp = EF_CTRL_EFUSE_CTRL_PROTECT | (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) -#if defined(CONFIG_SOC_SERIES_BL60X) +#if defined(CONFIG_SOC_SERIES_BL60X) || defined(CONFIG_SOC_SERIES_BL70X) | (EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) #endif | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) From e42d5f18aa04aac218408060038c91e33aea99cb Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:40:25 +0200 Subject: [PATCH 05/11] dts: pinctrl: Add bl70x pinctrl node This adds the pinctrl node Signed-off-by: Camille BAUD --- dts/riscv/bflb/bl70x.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/dts/riscv/bflb/bl70x.dtsi b/dts/riscv/bflb/bl70x.dtsi index 2a3164ebd5bf6..d9094ef0e49d2 100644 --- a/dts/riscv/bflb/bl70x.dtsi +++ b/dts/riscv/bflb/bl70x.dtsi @@ -6,6 +6,8 @@ #include #include +#include +#include / { #address-cells = <1>; @@ -67,6 +69,27 @@ zephyr,memory-region = "ITCM"; }; + pinctrl: pin-controller@40000000 { + compatible = "bflb,pinctrl"; + reg = <0x40000000 0x1000>; + ranges = <0x40000000 0x40000000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + + gpio0: gpio@40000000 { + compatible = "bflb,gpio"; + reg = <0x40000000 0x1000>; + #gpio-cells = <2>; + #bflb,pin-cells = <2>; + status = "disabled"; + + gpio-controller; + interrupts = <60 0>; + interrupt-parent = <&clic>; + }; + }; + efuse: efuse@40007000 { compatible = "bflb,efuse"; reg = <0x40007000 0x1000>; From 20f69a488cd4f4f3113be5297a533cb8fa008dfb Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:41:41 +0200 Subject: [PATCH 06/11] drivers: pinctrl: Update bflb pinctrl for bl70x BL70x = BL60x here Signed-off-by: Camille BAUD --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/pinctrl_bflb.c | 2 ++ drivers/pinctrl/pinctrl_bflb_bl60x_70x.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index d8a1ccd02b571..dd46c54f977b5 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -64,4 +64,5 @@ if (CONFIG_PINCTRL_BFLB) zephyr_library_sources(pinctrl_bflb.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_BL60X pinctrl_bflb_bl60x_70x.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_BL61X pinctrl_bflb_bl61x.c) + zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_BL70X pinctrl_bflb_bl60x_70x.c) endif() diff --git a/drivers/pinctrl/pinctrl_bflb.c b/drivers/pinctrl/pinctrl_bflb.c index 397b289edeeb1..c1c6a3a204bdf 100644 --- a/drivers/pinctrl/pinctrl_bflb.c +++ b/drivers/pinctrl/pinctrl_bflb.c @@ -13,6 +13,8 @@ #include #elif defined(CONFIG_SOC_SERIES_BL61X) #include +#elif defined(CONFIG_SOC_SERIES_BL70X) +#include #else #error "Unsupported Platform" #endif diff --git a/drivers/pinctrl/pinctrl_bflb_bl60x_70x.c b/drivers/pinctrl/pinctrl_bflb_bl60x_70x.c index f804e24d7d65d..26b0b92ea687d 100644 --- a/drivers/pinctrl/pinctrl_bflb_bl60x_70x.c +++ b/drivers/pinctrl/pinctrl_bflb_bl60x_70x.c @@ -13,6 +13,8 @@ #if defined(CONFIG_SOC_SERIES_BL60X) #include +#elif defined(CONFIG_SOC_SERIES_BL70X) +#include #else #error "Unsupported Platform" #endif From 57e47448f4e91d6ac1eaa3afea842e584950b617 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:43:43 +0200 Subject: [PATCH 07/11] dts: clock_control: Add bl70x clock nodes and bindings This adds the clock_control nodes and bindings Signed-off-by: Camille BAUD --- .../clock/bflb,bl70x-clock-controller.yaml | 15 ++++++ dts/bindings/clock/bflb,bl70x-dll.yaml | 20 +++++++ dts/bindings/clock/bflb,bl70x-root-clk.yaml | 23 ++++++++ dts/riscv/bflb/bl70x.dtsi | 52 +++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 dts/bindings/clock/bflb,bl70x-clock-controller.yaml create mode 100644 dts/bindings/clock/bflb,bl70x-dll.yaml create mode 100644 dts/bindings/clock/bflb,bl70x-root-clk.yaml diff --git a/dts/bindings/clock/bflb,bl70x-clock-controller.yaml b/dts/bindings/clock/bflb,bl70x-clock-controller.yaml new file mode 100644 index 0000000000000..0966dbdbd5cde --- /dev/null +++ b/dts/bindings/clock/bflb,bl70x-clock-controller.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: Bouffalolab BL70x Clock Controller + +compatible: "bflb,bl70x-clock-controller" + +include: [base.yaml, clock-controller.yaml] + +properties: + "#clock-cells": + const: 1 + +clock-cells: + - id diff --git a/dts/bindings/clock/bflb,bl70x-dll.yaml b/dts/bindings/clock/bflb,bl70x-dll.yaml new file mode 100644 index 0000000000000..a43707cf0e803 --- /dev/null +++ b/dts/bindings/clock/bflb,bl70x-dll.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: The BL70x DLL + +compatible: "bflb,bl70x-dll" + +include: [base.yaml, clock-controller.yaml] + +properties: + clocks: + type: phandle-array + required: true + description: source + + "#clock-cells": + const: 1 + +clock-cells: + - select diff --git a/dts/bindings/clock/bflb,bl70x-root-clk.yaml b/dts/bindings/clock/bflb,bl70x-root-clk.yaml new file mode 100644 index 0000000000000..15748b1664cf6 --- /dev/null +++ b/dts/bindings/clock/bflb,bl70x-root-clk.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: | + The BL70x Root Clock + +compatible: "bflb,bl70x-root-clk" + +include: [base.yaml, clock-controller.yaml] + +properties: + clocks: + type: phandle-array + required: true + description: source + + divider: + type: int + required: true + description: Divide source clock by this 8-bits value. Typically 1. + + "#clock-cells": + const: 0 diff --git a/dts/riscv/bflb/bl70x.dtsi b/dts/riscv/bflb/bl70x.dtsi index d9094ef0e49d2..c832ef5b10c51 100644 --- a/dts/riscv/bflb/bl70x.dtsi +++ b/dts/riscv/bflb/bl70x.dtsi @@ -8,11 +8,50 @@ #include #include #include +#include / { #address-cells = <1>; #size-cells = <1>; + clocks { + clk_rc32m: clk-rc32m { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "okay"; + }; + + clk_crystal: clk-crystal { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "okay"; + }; + + clk_pll: clk-pll { + #clock-cells = <1>; + compatible = "bflb,bl70x-dll"; + clocks = <&clk_crystal>; + status = "okay"; + }; + + clk_root: clk-root { + #clock-cells = <0>; + compatible = "bflb,bl70x-root-clk"; + clocks = <&clk_pll BL70X_DLL_144MHz>; + divider = <1>; + status = "okay"; + }; + + clk_bclk: clk-bclk { + #clock-cells = <0>; + compatible = "bflb,bclk"; + divider = <2>; + status = "okay"; + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -90,6 +129,19 @@ }; }; + clocks: clock-controller@40000000 { + compatible = "bflb,bl70x-clock-controller", "bflb,clock-controller"; + reg = <0x40000000 DT_SIZE_K(4)>; + #clock-cells = <1>; + status = "okay"; + clocks = <&clk_rc32m>, <&clk_crystal>, <&clk_root>, <&clk_bclk>, + <&clk_pll BL70X_DLL_144MHz>, <&clk_pll BL70X_DLL_96MHz>, + <&clk_pll BL70X_DLL_120MHz>, <&clk_pll BL70X_DLL_57MHz>; + clock-names = "rc32m", "crystal", "root", "bclk", + "dll_144", "dll_96", + "dll_120", "dll_57"; + }; + efuse: efuse@40007000 { compatible = "bflb,efuse"; reg = <0x40007000 0x1000>; From b52cacd501ec735a46dc05fbea903918e566b869 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:44:34 +0200 Subject: [PATCH 08/11] drivers: clock_control: Add BL70x clock control Adds clock_control driver for BL70x Signed-off-by: Camille BAUD --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig.bflb | 5 + drivers/clock_control/clock_control_bl70x.c | 761 ++++++++++++++++++ .../dt-bindings/clock/bflb_bl70x_clock.h | 23 + 4 files changed, 790 insertions(+) create mode 100644 drivers/clock_control/clock_control_bl70x.c create mode 100644 include/zephyr/dt-bindings/clock/bflb_bl70x_clock.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 47f4efe1a3944..f649af13c46e2 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -62,6 +62,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X clock_control_bl61x.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL70X clock_control_bl70x.c) if(CONFIG_CLOCK_CONTROL_RENESAS_RZA2M_CPG) zephyr_library_sources(clock_control_renesas_rza2m_cpg.c) diff --git a/drivers/clock_control/Kconfig.bflb b/drivers/clock_control/Kconfig.bflb index 4dd346fa269c8..234b74074caab 100644 --- a/drivers/clock_control/Kconfig.bflb +++ b/drivers/clock_control/Kconfig.bflb @@ -10,3 +10,8 @@ config CLOCK_CONTROL_BOUFFALOLAB_BL61X bool "Bouffalolab BL61x Clock Control Driver" default y depends on DT_HAS_BFLB_BL61X_CLOCK_CONTROLLER_ENABLED + +config CLOCK_CONTROL_BOUFFALOLAB_BL70X + bool "Bouffalolab BL70x Clock Control" + default y + depends on DT_HAS_BFLB_BL70X_CLOCK_CONTROLLER_ENABLED diff --git a/drivers/clock_control/clock_control_bl70x.c b/drivers/clock_control/clock_control_bl70x.c new file mode 100644 index 0000000000000..5568bbe5dfd87 --- /dev/null +++ b/drivers/clock_control/clock_control_bl70x.c @@ -0,0 +1,761 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bflb_bl70x_clock_controller + +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(clock_control_bl70x, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLK_SRC_IS(clk, src) \ + DT_SAME_NODE(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), 0), \ + DT_INST_CLOCKS_CTLR_BY_NAME(0, src)) + +#define CLOCK_TIMEOUT 1024 +#define EFUSE_RC32M_TRIM_OFFSET 0x0C +#define EFUSE_RC32M_TRIM_EN_POS 19 +#define EFUSE_RC32M_TRIM_PARITY_POS 18 +#define EFUSE_RC32M_TRIM_POS 10 +#define EFUSE_RC32M_TRIM_MSK 0x3FC00 + +enum bl70x_clkid { + bl70x_clkid_clk_root = BL70X_CLKID_CLK_ROOT, + bl70x_clkid_clk_rc32m = BL70X_CLKID_CLK_RC32M, + bl70x_clkid_clk_crystal = BL70X_CLKID_CLK_CRYSTAL, + bl70x_clkid_clk_dll = BL70X_CLKID_CLK_DLL, + bl70x_clkid_clk_bclk = BL70X_CLKID_CLK_BCLK, +}; + +struct clock_control_bl70x_dll_config { + enum bl70x_clkid source; + bool overclock; +}; + +struct clock_control_bl70x_root_config { + enum bl70x_clkid source; + uint8_t dll_select; + uint8_t divider; +}; + +struct clock_control_bl70x_bclk_config { + uint8_t divider; +}; + +struct clock_control_bl70x_data { + bool crystal_enabled; + bool dll_enabled; + struct clock_control_bl70x_dll_config dll; + struct clock_control_bl70x_root_config root; + struct clock_control_bl70x_bclk_config bclk; +}; + +static int clock_control_bl70x_deinit_crystal(void) +{ + uint32_t tmp; + + /* unpower crystal */ + tmp = sys_read32(AON_BASE + AON_RF_TOP_AON_OFFSET); + tmp = tmp & AON_PU_XTAL_AON_UMSK; + tmp = tmp & AON_PU_XTAL_BUF_AON_UMSK; + sys_write32(tmp, AON_BASE + AON_RF_TOP_AON_OFFSET); + + clock_bflb_settle(); + return 0; +} + +static int clock_control_bl70x_init_crystal(void) +{ + uint32_t tmp; + int count = CLOCK_TIMEOUT; + + /* power crystal */ + tmp = sys_read32(AON_BASE + AON_RF_TOP_AON_OFFSET); + tmp = (tmp & AON_PU_XTAL_AON_UMSK) | (1U << AON_PU_XTAL_AON_POS); + tmp = (tmp & AON_PU_XTAL_BUF_AON_UMSK) | (1U << AON_PU_XTAL_BUF_AON_POS); + sys_write32(tmp, AON_BASE + AON_RF_TOP_AON_OFFSET); + + /* wait for crystal to be powered on */ + do { + clock_bflb_settle(); + tmp = sys_read32(AON_BASE + AON_TSEN_OFFSET); + count--; + } while (!(tmp & AON_XTAL_RDY_MSK) && count > 0); + + clock_bflb_settle(); + if (count < 1) { + return -1; + } + return 0; +} + +/* HCLK is the core clock */ +static int clock_control_bl70x_set_root_clock_dividers(uint32_t hclk_div, uint32_t bclk_div) +{ + uint32_t tmp; + uint32_t old_rootclk; + + old_rootclk = clock_bflb_get_root_clock(); + + /* security RC32M */ + if (old_rootclk > 1) { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_RC32M); + } + + /* set dividers */ + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_HCLK_DIV_UMSK) | (hclk_div << GLB_REG_HCLK_DIV_POS); + tmp = (tmp & GLB_REG_BCLK_DIV_UMSK) | (bclk_div << GLB_REG_BCLK_DIV_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); + + /* do something undocumented, probably acknowledging clock change by disabling then + * reenabling bclk + */ + sys_write32(0x00000001, 0x40000FFC); + sys_write32(0x00000000, 0x40000FFC); + + clock_bflb_settle(); + + /* enable clocks */ + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_BCLK_EN_UMSK) | (1U << GLB_REG_BCLK_EN_POS); + tmp = (tmp & GLB_REG_HCLK_EN_UMSK) | (1U << GLB_REG_HCLK_EN_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); + + clock_bflb_set_root_clock(old_rootclk); + clock_bflb_settle(); + + return 0; +} + +static void clock_control_bl70x_set_machine_timer_clock_enable(bool enable) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); + if (enable) { + tmp = (tmp & GLB_CPU_RTC_EN_UMSK) | (1U << GLB_CPU_RTC_EN_POS); + } else { + tmp = (tmp & GLB_CPU_RTC_EN_UMSK) | (0U << GLB_CPU_RTC_EN_POS); + } + sys_write32(tmp, GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); +} + +/* clock: + * 0: BCLK + * 1: 32Khz Oscillator (RC32*K*) + */ +static void clock_control_bl70x_set_machine_timer_clock(bool enable, uint32_t clock, + uint32_t divider) +{ + uint32_t tmp; + + if (divider > 0x1FFFF) { + divider = 0x1FFFF; + } + if (clock > 1) { + clock = 1; + } + + /* disable first, then set div */ + clock_control_bl70x_set_machine_timer_clock_enable(false); + + tmp = sys_read32(GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); + tmp = (tmp & GLB_CPU_RTC_SEL_UMSK) | (clock << GLB_CPU_RTC_SEL_POS); + tmp = (tmp & GLB_CPU_RTC_DIV_UMSK) | (divider << GLB_CPU_RTC_DIV_POS); + sys_write32(tmp, GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); + + clock_control_bl70x_set_machine_timer_clock_enable(enable); +} + +static void clock_control_bl70x_deinit_dll(void) +{ + uint32_t tmp; + + + /* DLL Off */ + tmp = sys_read32(GLB_BASE + GLB_DLL_OFFSET); + tmp = (tmp & GLB_PPU_DLL_UMSK) | (0U << GLB_PPU_DLL_POS); + tmp = (tmp & GLB_PU_DLL_UMSK) | (0U << GLB_PU_DLL_POS); + tmp = (tmp & GLB_DLL_RESET_UMSK) | (1U << GLB_DLL_RESET_POS); + sys_write32(tmp, GLB_BASE + GLB_DLL_OFFSET); +} + +/* RC32M : 0 + * XTAL : 1 + */ +static void clock_control_bl70x_set_dll_source(uint32_t source) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_DLL_OFFSET); + if (source > 0) { + tmp = (tmp & GLB_DLL_REFCLK_SEL_UMSK) | (1U << GLB_DLL_REFCLK_SEL_POS); + } else { + tmp = (tmp & GLB_DLL_REFCLK_SEL_UMSK) | (0U << GLB_DLL_REFCLK_SEL_POS); + } + sys_write32(tmp, GLB_BASE + GLB_DLL_OFFSET); +} + +static void clock_control_bl70x_init_dll(enum bl70x_clkid source) +{ + uint32_t tmp; + uint32_t old_rootclk; + + old_rootclk = clock_bflb_get_root_clock(); + + /* security RC32M */ + if (old_rootclk > 1) { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_RC32M); + } + + clock_control_bl70x_deinit_dll(); + + if (source == BL70X_CLKID_CLK_CRYSTAL) { + clock_control_bl70x_set_dll_source(1); + } else { + clock_control_bl70x_set_dll_source(0); + } + + /* init sequence */ + tmp = sys_read32(GLB_BASE + GLB_DLL_OFFSET); + tmp = (tmp & GLB_DLL_PRECHG_SEL_UMSK) | (1U << GLB_DLL_PRECHG_SEL_POS); + sys_write32(tmp, GLB_BASE + GLB_DLL_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_DLL_OFFSET); + tmp = (tmp & GLB_PPU_DLL_UMSK) | (1U << GLB_PPU_DLL_POS); + sys_write32(tmp, GLB_BASE + GLB_DLL_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_DLL_OFFSET); + tmp = (tmp & GLB_PU_DLL_UMSK) | (1U << GLB_PU_DLL_POS); + sys_write32(tmp, GLB_BASE + GLB_DLL_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_DLL_OFFSET); + tmp = (tmp & GLB_DLL_RESET_UMSK) | (0U << GLB_DLL_RESET_POS); + sys_write32(tmp, GLB_BASE + GLB_DLL_OFFSET); + + clock_bflb_settle(); + + clock_bflb_set_root_clock(old_rootclk); + clock_bflb_settle(); +} + +/* + * 0: 57.6M + * 1: 96M + * 2: 144M + * 3: 120M (do not use) + */ +static void clock_control_bl70x_select_DLL(uint8_t dll) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_PLL_SEL_UMSK) | (dll << GLB_REG_PLL_SEL_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); +} + +static int clock_control_bl70x_clock_trim_32M(void) +{ + uint32_t tmp; + int err; + uint32_t trim, trim_parity; + const struct device *efuse = DEVICE_DT_GET_ONE(bflb_efuse); + + err = syscon_read_reg(efuse, EFUSE_RC32M_TRIM_OFFSET, &trim); + if (err < 0) { + LOG_ERR("Error: Couldn't read efuses: err: %d.\n", err); + return err; + } + if (!((trim >> EFUSE_RC32M_TRIM_EN_POS) & 1)) { + LOG_ERR("RC32M trim disabled!"); + return -EINVAL; + } + + trim_parity = (trim >> EFUSE_RC32M_TRIM_PARITY_POS) & 1; + trim = (trim & EFUSE_RC32M_TRIM_MSK) >> EFUSE_RC32M_TRIM_POS; + + if (trim_parity != (POPCOUNT(trim) & 1)) { + LOG_ERR("Bad trim parity"); + return -EINVAL; + } + + tmp = sys_read32(PDS_BASE + PDS_RC32M_CTRL0_OFFSET); + tmp = (tmp & PDS_RC32M_EXT_CODE_EN_UMSK) | 1 << PDS_RC32M_EXT_CODE_EN_POS; + tmp = (tmp & PDS_RC32M_CODE_FR_EXT_UMSK) | trim << PDS_RC32M_CODE_FR_EXT_POS; + sys_write32(tmp, PDS_BASE + PDS_RC32M_CTRL0_OFFSET); + + clock_bflb_settle(); + + return 0; +} + +/* source for most clocks, either XTAL or RC32M */ +static uint32_t clock_control_bl70x_get_xclk(const struct device *dev) +{ + uint32_t tmp; + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + tmp &= HBN_ROOT_CLK_SEL_MSK; + tmp = tmp >> HBN_ROOT_CLK_SEL_POS; + tmp &= 1; + /* on BL70x crystal can only be 32MHz */ + if (tmp == 0 || tmp == 1) { + return BFLB_RC32M_FREQUENCY; + } else { + return 0; + } +} + +static uint32_t clock_control_bl70x_get_clk(const struct device *dev) +{ + uint32_t tmp; + uint32_t hclk_div; + + hclk_div = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + hclk_div = (hclk_div & GLB_REG_HCLK_DIV_MSK) >> GLB_REG_HCLK_DIV_POS; + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + tmp &= HBN_ROOT_CLK_SEL_MSK; + tmp = (tmp >> HBN_ROOT_CLK_SEL_POS) >> 1; + tmp &= 1; + + if (tmp == 0) { + return clock_control_bl70x_get_xclk(dev) / (hclk_div + 1); + } + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_PLL_SEL_MSK) >> GLB_REG_PLL_SEL_POS; + if (tmp == 3) { + return MHZ(120) / (hclk_div + 1); + } else if (tmp == 2) { + return MHZ(144) / (hclk_div + 1); + } else if (tmp == 1) { + return MHZ(96) / (hclk_div + 1); + } else if (tmp == 0) { + return MHZ(57.6) / (hclk_div + 1); + } + return 0; +} + +/* most peripherals clock */ +static uint32_t clock_control_bl70x_get_bclk(const struct device *dev) +{ + uint32_t tmp; + uint32_t clock_id; + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_BCLK_DIV_MSK) >> GLB_REG_BCLK_DIV_POS; + clock_id = clock_control_bl70x_get_clk(dev); + return clock_id / (tmp + 1); +} + +static uint32_t clock_control_bl70x_mtimer_get_clk_src_div(const struct device *dev) +{ + return clock_control_bl70x_get_bclk(dev) / 1000 / 1000 - 1; +} + +static void clock_control_bl70x_cache_2T(bool yes) +{ + uint32_t tmp; + + tmp = sys_read32(L1C_BASE + L1C_CONFIG_OFFSET); + + if (yes) { + tmp |= L1C_IROM_2T_ACCESS_MSK; + } else { + tmp &= ~L1C_IROM_2T_ACCESS_MSK; + } + + sys_write32(tmp, L1C_BASE + L1C_CONFIG_OFFSET); +} + +static void clock_control_bl70x_init_root_as_dll(const struct device *dev) +{ + struct clock_control_bl70x_data *data = dev->data; + uint32_t tmp; + + clock_control_bl70x_init_dll(data->dll.source); + + /* enable all 'PDS' clocks / Divider out */ + tmp = sys_read32(GLB_BASE + GLB_DLL_OFFSET); + tmp = (tmp & GLB_DLL_CLK_57P6M_EN_UMSK) | (1U << GLB_DLL_CLK_57P6M_EN_POS); + tmp = (tmp & GLB_DLL_CLK_96M_EN_UMSK) | (1U << GLB_DLL_CLK_96M_EN_POS); + tmp = (tmp & GLB_DLL_CLK_144M_EN_UMSK) | (1U << GLB_DLL_CLK_144M_EN_POS); + tmp = (tmp & GLB_DLL_CLK_288M_EN_UMSK) | (1U << GLB_DLL_CLK_288M_EN_POS); + tmp = (tmp & GLB_DLL_CLK_MMDIV_EN_UMSK) | (1U << GLB_DLL_CLK_MMDIV_EN_POS); + sys_write32(tmp, GLB_BASE + GLB_DLL_OFFSET); + + /* glb enable dll actual? */ + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_PLL_EN_UMSK) | (1U << GLB_REG_PLL_EN_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); + + clock_control_bl70x_select_DLL(data->root.dll_select); + + if (data->dll.source == bl70x_clkid_clk_crystal) { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_PLL_XTAL); + } else { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_PLL_RC32M); + } + + if (clock_control_bl70x_get_clk(dev) > MHZ(120)) { + clock_control_bl70x_cache_2T(true); + } + + sys_write32(clock_control_bl70x_get_clk(dev), CORECLOCKREGISTER); +} + +static void clock_control_bl70x_init_root_as_crystal(const struct device *dev) +{ + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_XTAL); + sys_write32(clock_control_bl70x_get_clk(dev), CORECLOCKREGISTER); +} + +static int clock_control_bl70x_update_root(const struct device *dev) +{ + struct clock_control_bl70x_data *data = dev->data; + uint32_t tmp; + int ret; + + /* make sure all clocks are enabled */ + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_BCLK_EN_UMSK) | (1U << GLB_REG_BCLK_EN_POS); + tmp = (tmp & GLB_REG_HCLK_EN_UMSK) | (1U << GLB_REG_HCLK_EN_POS); + tmp = (tmp & GLB_REG_FCLK_EN_UMSK) | (1U << GLB_REG_FCLK_EN_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); + + /* set root clock to internal 32MHz Oscillator as failsafe */ + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_RC32M); + if (clock_control_bl70x_set_root_clock_dividers(0, 0) != 0) { + return -EIO; + } + sys_write32(BFLB_RC32M_FREQUENCY, CORECLOCKREGISTER); + + if (data->crystal_enabled) { + if (clock_control_bl70x_init_crystal() < 0) { + return -EIO; + } + } else { + clock_control_bl70x_deinit_crystal(); + } + + ret = clock_control_bl70x_set_root_clock_dividers(data->root.divider - 1, + data->bclk.divider - 1); + if (ret < 0) { + return ret; + } + + if (data->root.source == bl70x_clkid_clk_dll) { + clock_control_bl70x_init_root_as_dll(dev); + } else if (data->root.source == bl70x_clkid_clk_crystal) { + clock_control_bl70x_init_root_as_crystal(dev); + } else { + /* Root clock already setup as RC32M */ + } + + ret = clock_control_bl70x_clock_trim_32M(); + if (ret < 0) { + return ret; + } + clock_control_bl70x_set_machine_timer_clock( + 1, 0, clock_control_bl70x_mtimer_get_clk_src_div(dev)); + + clock_bflb_settle(); + + return ret; +} + +static void clock_control_bl70x_uart_set_clock_enable(bool enable) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG2_OFFSET); + if (enable) { + tmp = (tmp & GLB_UART_CLK_EN_UMSK) | (1U << GLB_UART_CLK_EN_POS); + } else { + tmp = (tmp & GLB_UART_CLK_EN_UMSK) | (0U << GLB_UART_CLK_EN_POS); + } + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG2_OFFSET); +} + +/* Clock: + * FCLK: 0 + * 96 MHz DLL: 1 + * When using DLL root clock, we can use either setting, when using the 32Mhz Oscillator with a + * uninitialized DLL, only FCLK will be available. + */ +static void clock_control_bl70x_uart_set_clock(bool enable, uint32_t clock, uint32_t divider) +{ + uint32_t tmp; + + if (divider > 0x7) { + divider = 0x7; + } + if (clock > 1) { + clock = 1; + } + /* disable uart clock */ + clock_control_bl70x_uart_set_clock_enable(false); + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG2_OFFSET); + tmp = (tmp & GLB_UART_CLK_DIV_UMSK) | (divider << GLB_UART_CLK_DIV_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG2_OFFSET); + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + tmp = (tmp & HBN_UART_CLK_SEL_UMSK) | (clock << HBN_UART_CLK_SEL_POS); + sys_write32(tmp, HBN_BASE + HBN_GLB_OFFSET); + + clock_control_bl70x_uart_set_clock_enable(enable); +} + +/* Simple function to enable all peripherals for now */ +static void clock_control_bl70x_peripheral_clock_init(void) +{ + uint32_t regval = sys_read32(GLB_BASE + GLB_CGEN_CFG1_OFFSET); + + /* enable ADC clock routing */ + regval |= (1 << 2); + /* enable UART0 clock routing */ + regval |= (1 << 16); + /* enable I2C0 clock routing */ + regval |= (1 << 19); + + sys_write32(regval, GLB_BASE + GLB_CGEN_CFG1_OFFSET); + + clock_control_bl70x_uart_set_clock(1, 0, 0); +} + +static int clock_control_bl70x_on(const struct device *dev, clock_control_subsys_t sys) +{ + struct clock_control_bl70x_data *data = dev->data; + int ret = -EINVAL; + uint32_t key; + enum bl70x_clkid oldroot; + + key = irq_lock(); + + if ((enum bl70x_clkid)sys == bl70x_clkid_clk_crystal) { + if (data->crystal_enabled) { + ret = 0; + } else { + data->crystal_enabled = true; + ret = clock_control_bl70x_update_root(dev); + if (ret < 0) { + data->crystal_enabled = false; + } + } + } else if ((enum bl70x_clkid)sys == bl70x_clkid_clk_dll) { + if (data->dll_enabled) { + ret = 0; + } else { + data->dll_enabled = true; + ret = clock_control_bl70x_update_root(dev); + if (ret < 0) { + data->dll_enabled = false; + } + } + } else if ((int)sys == BFLB_FORCE_ROOT_RC32M) { + if (data->root.source == bl70x_clkid_clk_rc32m) { + ret = 0; + } else { + /* Cannot fail to set root to rc32m */ + data->root.source = bl70x_clkid_clk_rc32m; + ret = clock_control_bl70x_update_root(dev); + } + } else if ((int)sys == BFLB_FORCE_ROOT_CRYSTAL) { + if (data->root.source == bl70x_clkid_clk_crystal) { + ret = 0; + } else { + oldroot = data->root.source; + data->root.source = bl70x_clkid_clk_crystal; + ret = clock_control_bl70x_update_root(dev); + if (ret < 0) { + data->root.source = oldroot; + } + } + } else if ((int)sys == BFLB_FORCE_ROOT_PLL) { + if (data->root.source == bl70x_clkid_clk_dll) { + ret = 0; + } else { + oldroot = data->root.source; + data->root.source = bl70x_clkid_clk_dll; + ret = clock_control_bl70x_update_root(dev); + if (ret < 0) { + data->root.source = oldroot; + } + } + } + + irq_unlock(key); + return ret; +} + +static int clock_control_bl70x_off(const struct device *dev, clock_control_subsys_t sys) +{ + struct clock_control_bl70x_data *data = dev->data; + int ret = -EINVAL; + uint32_t key; + + key = irq_lock(); + + if ((enum bl70x_clkid)sys == bl70x_clkid_clk_crystal) { + if (!data->crystal_enabled) { + ret = 0; + } else { + data->crystal_enabled = false; + ret = clock_control_bl70x_update_root(dev); + if (ret < 0) { + data->crystal_enabled = true; + } + } + } else if ((enum bl70x_clkid)sys == bl70x_clkid_clk_dll) { + if (!data->dll_enabled) { + ret = 0; + } else { + data->dll_enabled = false; + ret = clock_control_bl70x_update_root(dev); + if (ret < 0) { + data->dll_enabled = true; + } + } + } + + irq_unlock(key); + return ret; +} + +static enum clock_control_status clock_control_bl70x_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + struct clock_control_bl70x_data *data = dev->data; + + switch ((enum bl70x_clkid)sys) { + case bl70x_clkid_clk_root: + case bl70x_clkid_clk_bclk: + case bl70x_clkid_clk_rc32m: + return CLOCK_CONTROL_STATUS_ON; + case bl70x_clkid_clk_crystal: + if (data->crystal_enabled) { + return CLOCK_CONTROL_STATUS_ON; + } + return CLOCK_CONTROL_STATUS_OFF; + case bl70x_clkid_clk_dll: + if (data->dll_enabled) { + return CLOCK_CONTROL_STATUS_ON; + } + return CLOCK_CONTROL_STATUS_OFF; + default: + return CLOCK_CONTROL_STATUS_UNKNOWN; + } +} + +static int clock_control_bl70x_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + if ((enum bl70x_clkid)sys == bl70x_clkid_clk_root) { + *rate = clock_control_bl70x_get_clk(dev); + } else if ((enum bl70x_clkid)sys == bl70x_clkid_clk_bclk) { + *rate = clock_control_bl70x_get_bclk(dev); + } else if ((enum bl70x_clkid)sys == bl70x_clkid_clk_crystal) { + *rate = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), clock_frequency); + } else if ((enum bl70x_clkid)sys == bl70x_clkid_clk_rc32m) { + *rate = BFLB_RC32M_FREQUENCY; + } else { + return -EINVAL; + } + return 0; +} + +static int clock_control_bl70x_init(const struct device *dev) +{ + int ret; + uint32_t key; + + key = irq_lock(); + + ret = clock_control_bl70x_update_root(dev); + if (ret < 0) { + irq_unlock(key); + return ret; + } + + clock_control_bl70x_peripheral_clock_init(); + + clock_bflb_settle(); + + irq_unlock(key); + + return 0; +} + +static DEVICE_API(clock_control, clock_control_bl70x_api) = { + .on = clock_control_bl70x_on, + .off = clock_control_bl70x_off, + .get_rate = clock_control_bl70x_get_rate, + .get_status = clock_control_bl70x_get_status, +}; + +static struct clock_control_bl70x_data clock_control_bl70x_data = { + .crystal_enabled = DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal)), + .dll_enabled = DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, dll_144)), + + .root = { +#if CLK_SRC_IS(root, dll_144) + .source = bl70x_clkid_clk_dll, + .dll_select = DT_CLOCKS_CELL(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), select), +#elif CLK_SRC_IS(root, crystal) + .source = bl70x_clkid_clk_crystal, +#else + .source = bl70x_clkid_clk_rc32m, +#endif + .divider = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), divider), + }, + + .dll = { +#if CLK_SRC_IS(dll_144, crystal) + .source = bl70x_clkid_clk_crystal, +#else + .source = bl70x_clkid_clk_rc32m, +#endif + }, + + .bclk = { + .divider = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, bclk), divider), + }, +}; + +BUILD_ASSERT(CLK_SRC_IS(dll_144, crystal) || CLK_SRC_IS(root, crystal) + ? DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal)) + : 1, + "Crystal must be enabled to use it"); + +BUILD_ASSERT(CLK_SRC_IS(root, dll_144) ? + DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, dll_144)) : 1, + "PLL must be enabled to use it"); + +BUILD_ASSERT(DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, rc32m)), "RC32M is always on"); + +BUILD_ASSERT(DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rc32m), clock_frequency) + == BFLB_RC32M_FREQUENCY, "RC32M must be 32M"); + +BUILD_ASSERT(DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), clock_frequency) + == BFLB_RC32M_FREQUENCY, "Crystal must be 32M for BL70x"); + +DEVICE_DT_INST_DEFINE(0, clock_control_bl70x_init, NULL, &clock_control_bl70x_data, + NULL, PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &clock_control_bl70x_api); diff --git a/include/zephyr/dt-bindings/clock/bflb_bl70x_clock.h b/include/zephyr/dt-bindings/clock/bflb_bl70x_clock.h new file mode 100644 index 0000000000000..e88995dbf9a81 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/bflb_bl70x_clock.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_BFLB_BL70X_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_BFLB_BL70X_CLOCK_H_ + +#include "bflb_clock_common.h" + +#define BL70X_CLKID_CLK_ROOT BFLB_CLKID_CLK_ROOT +#define BL70X_CLKID_CLK_RC32M BFLB_CLKID_CLK_RC32M +#define BL70X_CLKID_CLK_CRYSTAL BFLB_CLKID_CLK_CRYSTAL +#define BL70X_CLKID_CLK_BCLK BFLB_CLKID_CLK_BCLK +#define BL70X_CLKID_CLK_DLL 4 + +#define BL70X_DLL_57MHz 0 +#define BL70X_DLL_96MHz 1 +#define BL70X_DLL_144MHz 2 +#define BL70X_DLL_120MHz 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_BFLB_BL70X_CLOCK_H_ */ From 7e7a04e0906f04401574c54304e50995d6ee698d Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:46:20 +0200 Subject: [PATCH 09/11] dts: uart: Add uart node to BL70x Adds the uart node for BL70x Signed-off-by: Camille BAUD --- dts/riscv/bflb/bl70x.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dts/riscv/bflb/bl70x.dtsi b/dts/riscv/bflb/bl70x.dtsi index c832ef5b10c51..b1cb14ed25d26 100644 --- a/dts/riscv/bflb/bl70x.dtsi +++ b/dts/riscv/bflb/bl70x.dtsi @@ -149,6 +149,22 @@ size = <128>; }; + uart0: uart@4000a000 { + compatible = "bflb,uart"; + reg = <0x4000a000 0x100>; + interrupts = <45 0>; + interrupt-parent = <&clic>; + status = "disabled"; + }; + + uart1: uart@4000a100 { + compatible = "bflb,uart"; + reg = <0x4000a100 0x100>; + interrupts = <46 0>; + interrupt-parent = <&clic>; + status = "disabled"; + }; + flashctrl: flash-controller@4000b000 { compatible = "bflb,flash-controller"; reg = <0x4000b000 0x1000>; From f47e5e6e7922c5df856c954ebba69b8f41e2ff75 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:47:26 +0200 Subject: [PATCH 10/11] drivers: uart: Update bflb uart driver for BL70x BL70x almost equal BL60x here Signed-off-by: Camille BAUD --- drivers/serial/uart_bflb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/uart_bflb.c b/drivers/serial/uart_bflb.c index cbdd667a24864..22acaadf40f58 100644 --- a/drivers/serial/uart_bflb.c +++ b/drivers/serial/uart_bflb.c @@ -79,7 +79,7 @@ static uint32_t uart_bflb_get_clock(void) uint32_t uclk; const struct device *clock_ctrl = DEVICE_DT_GET_ANY(bflb_clock_controller); -#if defined(CONFIG_SOC_SERIES_BL60X) +#if defined(CONFIG_SOC_SERIES_BL60X) || defined(CONFIG_SOC_SERIES_BL70X) uart_divider = sys_read32(GLB_BASE + GLB_CLK_CFG2_OFFSET); uart_divider = (uart_divider & GLB_UART_CLK_DIV_MSK) >> GLB_UART_CLK_DIV_POS; clock_control_get_rate(clock_ctrl, (void *)BFLB_CLKID_CLK_ROOT, &uclk); From 0580526d4f60f448a52874e52359647352040581 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Mon, 4 Aug 2025 07:48:03 +0200 Subject: [PATCH 11/11] boards: add dt_xt_zb1_devkit Introduce a bl70x board. Signed-off-by: Camille BAUD --- .../dt_xt_zb1_devkit/Kconfig.dt_xt_zb1_devkit | 5 + boards/doiting/dt_xt_zb1_devkit/board.cmake | 25 +++++ boards/doiting/dt_xt_zb1_devkit/board.yml | 6 ++ .../doc/img/dt_xt_zb1_devkit.webp | Bin 0 -> 30236 bytes boards/doiting/dt_xt_zb1_devkit/doc/index.rst | 92 ++++++++++++++++++ .../dt_xt_zb1_devkit-pinctrl.dtsi | 25 +++++ .../dt_xt_zb1_devkit/dt_xt_zb1_devkit.dts | 63 ++++++++++++ .../dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml | 18 ++++ .../dt_xt_zb1_devkit_defconfig | 8 ++ .../dt_xt_zb1_devkit/support/bl70x.cfg | 80 +++++++++++++++ .../dt_xt_zb1_devkit/support/openocd.cfg | 5 + 11 files changed, 327 insertions(+) create mode 100644 boards/doiting/dt_xt_zb1_devkit/Kconfig.dt_xt_zb1_devkit create mode 100644 boards/doiting/dt_xt_zb1_devkit/board.cmake create mode 100644 boards/doiting/dt_xt_zb1_devkit/board.yml create mode 100644 boards/doiting/dt_xt_zb1_devkit/doc/img/dt_xt_zb1_devkit.webp create mode 100644 boards/doiting/dt_xt_zb1_devkit/doc/index.rst create mode 100644 boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit-pinctrl.dtsi create mode 100644 boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.dts create mode 100644 boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml create mode 100644 boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit_defconfig create mode 100644 boards/doiting/dt_xt_zb1_devkit/support/bl70x.cfg create mode 100644 boards/doiting/dt_xt_zb1_devkit/support/openocd.cfg diff --git a/boards/doiting/dt_xt_zb1_devkit/Kconfig.dt_xt_zb1_devkit b/boards/doiting/dt_xt_zb1_devkit/Kconfig.dt_xt_zb1_devkit new file mode 100644 index 0000000000000..0f1b7823c6727 --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/Kconfig.dt_xt_zb1_devkit @@ -0,0 +1,5 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_DT_XT_ZB1_DEVKIT + select SOC_BL702C10Q2H diff --git a/boards/doiting/dt_xt_zb1_devkit/board.cmake b/boards/doiting/dt_xt_zb1_devkit/board.cmake new file mode 100644 index 0000000000000..f5f09ea04022a --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/board.cmake @@ -0,0 +1,25 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(openocd --cmd-pre-init "source [find bl70x.cfg]") + +board_runner_args(openocd --use-elf --no-load --no-init) +board_runner_args(openocd --gdb-init "set mem inaccessible-by-default off") +board_runner_args(openocd --gdb-init "set architecture riscv:rv32") +board_runner_args(openocd --gdb-init "set remotetimeout 250") +board_runner_args(openocd --gdb-init "set print asm-demangle on") +board_runner_args(openocd --gdb-init "set backtrace limit 32") +board_runner_args(openocd --gdb-init "mem 0x22010000 0x22014000 rw") +board_runner_args(openocd --gdb-init "mem 0x42010000 0x42014000 rw") +board_runner_args(openocd --gdb-init "mem 0x22014000 0x22020000 rw") +board_runner_args(openocd --gdb-init "mem 0x42014000 0x42020000 rw") +board_runner_args(openocd --gdb-init "mem 0x22020000 0x2203C000 rw") +board_runner_args(openocd --gdb-init "mem 0x42020000 0x4203C000 rw") +board_runner_args(openocd --gdb-init "mem 0x23000000 0x23400000 ro") +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) + +board_runner_args(bflb_mcu_tool --chipname bl702) +include(${ZEPHYR_BASE}/boards/common/bflb_mcu_tool.board.cmake) + +board_set_flasher(bflb_mcu_tool) diff --git a/boards/doiting/dt_xt_zb1_devkit/board.yml b/boards/doiting/dt_xt_zb1_devkit/board.yml new file mode 100644 index 0000000000000..d3b1d9836ec07 --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/board.yml @@ -0,0 +1,6 @@ +board: + name: dt_xt_zb1_devkit + full_name: XT-ZB1 Zigbee 3.0 and BLE 5.0 Coexistence Module Development Kit + vendor: doiting + socs: + - name: bl702c10q2h diff --git a/boards/doiting/dt_xt_zb1_devkit/doc/img/dt_xt_zb1_devkit.webp b/boards/doiting/dt_xt_zb1_devkit/doc/img/dt_xt_zb1_devkit.webp new file mode 100644 index 0000000000000000000000000000000000000000..302b7d7f97a6fc63c6e92b06aa44f50c9830cb0d GIT binary patch literal 30236 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 + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = , + ; + bias-pull-up; + input-schmitt-enable; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + pinmux = , + ; + bias-high-impedance; + }; + }; +}; diff --git a/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.dts b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.dts new file mode 100644 index 0000000000000..79c17e5574320 --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.dts @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "dt_xt_zb1_devkit-pinctrl.dtsi" + +/ { + model = "Zigbee 3.0 and BLE 5.0 Coexistence Module Development Kit"; + compatible = "bflb,bl702"; + + chosen { + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&flashctrl { + flash0: flash@23000000 { + compatible = "soc-nv-flash", "mxicy,kh25v80"; + reg = <0x23000000 (0x1000000 - 0x2000)>; + write-block-size = <256>; + erase-block-size = ; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x00000000 0x80000>; + read-only; + }; + + storage_partition: partition@80000 { + label = "storage"; + reg = <0x00080000 (0x80000 - 0x2000)>; + }; + }; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml new file mode 100644 index 0000000000000..f53ad69ef354f --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +identifier: dt_xt_zb1_devkit +name: Zigbee 3.0 and BLE 5.0 Coexistence Module Development Kitt +type: mcu +arch: riscv +ram: 132 +toolchain: + - zephyr +testing: + ignore_tags: + - net + - bluetooth +supported: + - pinctrl + - uart +vendor: doiting diff --git a/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit_defconfig b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit_defconfig new file mode 100644 index 0000000000000..b4c911b77c403 --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit_defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021-2025 ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y + +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/doiting/dt_xt_zb1_devkit/support/bl70x.cfg b/boards/doiting/dt_xt_zb1_devkit/support/bl70x.cfg new file mode 100644 index 0000000000000..eb4b3c90550df --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/support/bl70x.cfg @@ -0,0 +1,80 @@ +# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME riscv +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +if { [info exists WORKAREAADDR] } { + set _WORKAREAADDR $WORKAREAADDR +} else { + set _WORKAREAADDR 0x22020000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x20000e05 +} + +transport select jtag +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME + +$_TARGETNAME.0 configure -work-area-phys $_WORKAREAADDR -work-area-size $_WORKAREASIZE -work-area-backup 1 + +echo "Ready for Remote Connections" + +$_TARGETNAME.0 configure -event reset-assert-pre { + echo "reset-assert-pre" + adapter speed 400 +} + +$_TARGETNAME.0 configure -event reset-deassert-post { + echo "reset-deassert-post" + + adapter speed 400 + + reg mstatus 0x0 + reg pc 0x21000000 +} + +$_TARGETNAME.0 configure -event reset-init { + echo "reset-init" + + adapter speed 400 +} + +$_TARGETNAME.0 configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME.0 configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +gdb_memory_map enable +gdb_flash_program enable + +# 'progbuf', 'sysbus' or 'abstract' +riscv set_mem_access sysbus +riscv set_command_timeout_sec 1 + +init +reset init + +reset init diff --git a/boards/doiting/dt_xt_zb1_devkit/support/openocd.cfg b/boards/doiting/dt_xt_zb1_devkit/support/openocd.cfg new file mode 100644 index 0000000000000..ea9daa4d8b525 --- /dev/null +++ b/boards/doiting/dt_xt_zb1_devkit/support/openocd.cfg @@ -0,0 +1,5 @@ +# For WCH linkE in DAP mode + +interface cmsis-dap + +adapter speed 400