From b169a8953ea7890fcaa6f5455154a52e1bf30541 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sat, 31 Aug 2024 19:04:58 +0200 Subject: [PATCH 01/21] drivers: timer: Enable clic riscv machine timer Enable the suport to sifive,clic machine timer. Signed-off-by: Gerson Fernando Budke --- drivers/timer/Kconfig.riscv_machine | 1 + drivers/timer/riscv_machine_timer.c | 11 +++++++++++ .../interrupt-controller/sifive,clic.yaml | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 dts/bindings/interrupt-controller/sifive,clic.yaml diff --git a/drivers/timer/Kconfig.riscv_machine b/drivers/timer/Kconfig.riscv_machine index efbd4d322f731..19167ebe6d743 100644 --- a/drivers/timer/Kconfig.riscv_machine +++ b/drivers/timer/Kconfig.riscv_machine @@ -9,6 +9,7 @@ config RISCV_MACHINE_TIMER depends on DT_HAS_ANDESTECH_MACHINE_TIMER_ENABLED || \ DT_HAS_NEORV32_MACHINE_TIMER_ENABLED || \ DT_HAS_NUCLEI_SYSTIMER_ENABLED || \ + DT_HAS_SIFIVE_CLIC_ENABLED || \ DT_HAS_SIFIVE_CLINT0_ENABLED || \ DT_HAS_TELINK_MACHINE_TIMER_ENABLED || \ DT_HAS_LOWRISC_MACHINE_TIMER_ENABLED || \ diff --git a/drivers/timer/riscv_machine_timer.c b/drivers/timer/riscv_machine_timer.c index 36e29c6aadb31..244405e40189d 100644 --- a/drivers/timer/riscv_machine_timer.c +++ b/drivers/timer/riscv_machine_timer.c @@ -13,6 +13,8 @@ #include #include +/* clang-format off */ + /* andestech,machine-timer */ #if DT_HAS_COMPAT_STATUS_OKAY(andestech_machine_timer) #define DT_DRV_COMPAT andestech_machine_timer @@ -34,6 +36,13 @@ #define MTIME_REG DT_INST_REG_ADDR(0) #define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 8) #define TIMER_IRQN DT_INST_IRQ_BY_IDX(0, 1, irq) +/* sifive,clic */ +#elif DT_HAS_COMPAT_STATUS_OKAY(sifive_clic) +#define DT_DRV_COMPAT sifive_clic + +#define MTIME_REG (DT_INST_REG_ADDR(0) + 0xbff8U) +#define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 0x4000U) +#define TIMER_IRQN DT_INST_IRQ_BY_IDX(0, 1, irq) /* sifive,clint0 */ #elif DT_HAS_COMPAT_STATUS_OKAY(sifive_clint0) #define DT_DRV_COMPAT sifive_clint0 @@ -105,6 +114,8 @@ #define CYCLES_MAX_4 (CYCLES_MAX_3 / 2 + CYCLES_MAX_3 / 4) #define CYCLES_MAX (CYCLES_MAX_4 + LSB_GET(CYCLES_MAX_4)) +/* clang-format on */ + static struct k_spinlock lock; static uint64_t last_count; static uint64_t last_ticks; diff --git a/dts/bindings/interrupt-controller/sifive,clic.yaml b/dts/bindings/interrupt-controller/sifive,clic.yaml new file mode 100644 index 0000000000000..dbc31e8ba1007 --- /dev/null +++ b/dts/bindings/interrupt-controller/sifive,clic.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2021, Tokita, Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: SiFive CLIC interrupt controller + +compatible: "sifive,clic" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#interrupt-cells": + const: 2 + +interrupt-cells: + - irq + - priority From c71987d8d3d98be2f06a2cc7bb27de0e2372424e Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sat, 17 Jul 2021 22:49:40 -0300 Subject: [PATCH 02/21] west: Introduce hal bouffalo lab Add initial version that uses bouffalo_sdk 1.4.2. Signed-off-by: Gerson Fernando Budke --- modules/Kconfig | 3 + modules/hal_bouffalolab/CMakeLists.txt | 61 +++++++++++++++++++ modules/hal_bouffalolab/Kconfig | 59 ++++++++++++++++++ .../hal_bouffalolab/include/bl_ld_sections.h | 25 ++++++++ west.yml | 8 +++ 5 files changed, 156 insertions(+) create mode 100644 modules/hal_bouffalolab/CMakeLists.txt create mode 100644 modules/hal_bouffalolab/Kconfig create mode 100644 modules/hal_bouffalolab/include/bl_ld_sections.h diff --git a/modules/Kconfig b/modules/Kconfig index a8cf861a68096..491e20baf1c74 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -66,6 +66,9 @@ comment "Unavailable modules, please install those via the project manifest." # config ZEPHYR__MODULE # bool +comment "hal_bouffalolab module not available." + depends on !ZEPHYR_HAL_BOUFFALOLAB_MODULE + comment "hal_gigadevice module not available." depends on !ZEPHYR_HAL_GIGADEVICE_MODULE diff --git a/modules/hal_bouffalolab/CMakeLists.txt b/modules/hal_bouffalolab/CMakeLists.txt new file mode 100644 index 0000000000000..6f7cd0437b731 --- /dev/null +++ b/modules/hal_bouffalolab/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (c) 2021-2024 Gerson Fernando Budke +# +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_SOC_FAMILY_BFLB) + +zephyr_library_named(hal_bouffalolab) + +zephyr_compile_definitions( + ARCH_RISCV +) + +zephyr_library_compile_definitions( + BFLB_USE_HAL_DRIVER + BFLB_USE_CUSTOM_LD_SECTIONS +) + +set(bflb_soc ${CONFIG_SOC_SUB_SERIES}) +set(bflb_drv_dir ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/drivers/${bflb_soc}_driver) +set(bflb_common_dir ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/common) +set(bflb_drv_src_dir ${bflb_drv_dir}/std_drv/src) + +# Global includes to be used outside hal_gigadevice +zephyr_include_directories( + include + ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/include + + ${bflb_drv_dir}/regs + ${bflb_drv_dir}/startup + ${bflb_drv_dir}/std_drv/inc + + ${bflb_common_dir}/misc +) + +zephyr_library_include_directories( + ${bflb_common_dir}/soft_crc +) + +zephyr_library_sources( + ${bflb_drv_src_dir}/${bflb_soc}_aon.c + ${bflb_drv_src_dir}/${bflb_soc}_ef_ctrl.c + ${bflb_drv_src_dir}/${bflb_soc}_glb.c + ${bflb_drv_src_dir}/${bflb_soc}_hbn.c + ${bflb_drv_src_dir}/${bflb_soc}_l1c.c + ${bflb_drv_src_dir}/${bflb_soc}_pds.c + ${bflb_drv_src_dir}/${bflb_soc}_romapi.c + + ${bflb_common_dir}/soft_crc/softcrc.c +) + +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_ACOMP ${bflb_drv_src_dir}/${bflb_soc}_acomp.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_ADC ${bflb_drv_src_dir}/${bflb_soc}_adc.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_DAC ${bflb_drv_src_dir}/${bflb_soc}_dac.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_DMA ${bflb_drv_src_dir}/${bflb_soc}_dma.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_I2C ${bflb_drv_src_dir}/${bflb_soc}_i2c.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_IR ${bflb_drv_src_dir}/${bflb_soc}_ir.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_PWM ${bflb_drv_src_dir}/${bflb_soc}_pwm.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_SPI ${bflb_drv_src_dir}/${bflb_soc}_spi.c) +zephyr_library_sources_ifdef(CONFIG_USE_BFLB_UART ${bflb_drv_src_dir}/${bflb_soc}_uart.c) + +endif() diff --git a/modules/hal_bouffalolab/Kconfig b/modules/hal_bouffalolab/Kconfig new file mode 100644 index 0000000000000..2e753a1da5341 --- /dev/null +++ b/modules/hal_bouffalolab/Kconfig @@ -0,0 +1,59 @@ +# Copyright (c) 2021-2024 Gerson Fernando Budke +# +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_HAL_BOUFFALOLAB_MODULE + bool + +config HAS_BFLB_HAL + bool + +if HAS_BFLB_HAL + +config USE_BFLB_ACOMP + bool + help + Enable BFLB Analog Comparator (ACOMP) HAL module driver + +config USE_BFLB_ADC + bool + help + Enable BFLB Analog-to-Digital Converter (ADC) HAL module driver + +config USE_BFLB_DAC + bool + help + Enable BFLB Digital-to-Analog Converter (DAC) HAL module driver + +config USE_BFLB_DMA + bool + help + Enable BFLB Direct Memory Access controller (DMA) HAL module driver + +config USE_BFLB_I2C + bool + help + Enable BFLB Inter-Integrated Circuit Interface (I2C) HAL module driver + +config USE_BFLB_IR + bool + help + Enable BFLB Infrared Remote controller (IR) HAL module driver + +config USE_BFLB_PWM + bool + help + Enable BFLB Pulse Width Modulation (PMU) HAL module driver + +config USE_BFLB_SPI + bool + help + Enable BFLB Serial Peripheral Interface(SPI) HAL module driver + +config USE_BFLB_UART + bool + help + Enable BFLB Universal Asynchronous Receiver/Transmitter (UART) + HAL module driver + +endif # HAS_BFLB_HAL diff --git a/modules/hal_bouffalolab/include/bl_ld_sections.h b/modules/hal_bouffalolab/include/bl_ld_sections.h new file mode 100644 index 0000000000000..c06ae56e65f84 --- /dev/null +++ b/modules/hal_bouffalolab/include/bl_ld_sections.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __BL_LD_SECTIONS_H +#define __BL_LD_SECTIONS_H + +#define ATTR_STRINGIFY(x) #x +#define ATTR_TOSTRING(x) ATTR_STRINGIFY(x) +#define ATTR_UNI_SYMBOL __FILE__ ATTR_TOSTRING(__LINE__) +#define ATTR_CLOCK_SECTION __attribute__((section(".itcm.sclock_rlt_code." ATTR_UNI_SYMBOL))) +#define ATTR_CLOCK_CONST_SECTION __attribute__((section(".itcm.sclock_rlt_const." ATTR_UNI_SYMBOL))) +#define ATTR_TCM_SECTION __attribute__((section(".itcm.code." ATTR_UNI_SYMBOL))) +#define ATTR_TCM_CONST_SECTION __attribute__((section(".itcm.const." ATTR_UNI_SYMBOL))) +#define ATTR_DTCM_SECTION __attribute__((section(".dtcm.data"))) +#define ATTR_HSRAM_SECTION __attribute__((section(".hsram_code"))) +#define ATTR_DMA_RAM_SECTION __attribute__((section(".system_ram"))) +#define ATTR_HBN_RAM_SECTION __attribute__((section(".hbn_ram_code"))) +#define ATTR_HBN_RAM_CONST_SECTION __attribute__((section(".hbn_ram_data"))) +#define ATTR_FALLTHROUGH() __attribute__((fallthrough)) +#define ATTR_USED __attribute__((__used__)) +#define ATTR_EALIGN(x) __aligned(size) + +#endif /* __BL_LD_SECTIONS_H */ diff --git a/west.yml b/west.yml index ca7b56f7e65fd..7d542993c55bb 100644 --- a/west.yml +++ b/west.yml @@ -23,6 +23,8 @@ manifest: url-base: https://github.com/zephyrproject-rtos - name: babblesim url-base: https://github.com/BabbleSim + - name: nandojve + url-base: https://github.com/nandojve group-filter: [-babblesim, -optional] @@ -161,6 +163,12 @@ manifest: path: modules/hal/atmel groups: - hal + - name: hal_bouffalolab + remote: nandojve + path: modules/hal/bouffalolab + revision: sdk-v1.4.5 + groups: + - hal - name: hal_espressif revision: e52371024732a47a67fa9c889fbccd0aa6355f3a path: modules/hal/espressif From 0d79fd01cef34e8027b0c61435af0c22f4d4676d Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 14 Oct 2024 20:38:17 +0200 Subject: [PATCH 03/21] dts: bindings: vendor-prefixes: Add Bouffalo Lab prefix Add necessary bflb prefix to be used on devicetree bindings and identify the board vendor. Signed-off-by: Gerson Fernando Budke --- 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 ee115b920f6fd..2f3a79c9247c7 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -100,6 +100,7 @@ bbc BBC bcdevices Blue Clover Devices beacon Compass Electronics Group, LLC beagle BeagleBoard.org Foundation +bflb Bouffalo Lab (Nanjing) Co., Ltd. bhf Beckhoff Automation GmbH & Co. KG bitmain Bitmain Technologies blues Blues Wireless From 60d45620b76433077275c7d6ea14054b82eedf0a Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 2 Aug 2021 22:54:21 -0300 Subject: [PATCH 04/21] dts: riscv: bouffalolab: Add bl6 series cpu Introduce Bouffalo Lab vendor with BL602 cpu. Signed-off-by: Gerson Fernando Budke --- dts/riscv/bouffalolab/bl6.dtsi | 96 ++++++++++++++++++++++++++++++++ dts/riscv/bouffalolab/bl602.dtsi | 15 +++++ 2 files changed, 111 insertions(+) create mode 100644 dts/riscv/bouffalolab/bl6.dtsi create mode 100644 dts/riscv/bouffalolab/bl602.dtsi diff --git a/dts/riscv/bouffalolab/bl6.dtsi b/dts/riscv/bouffalolab/bl6.dtsi new file mode 100644 index 0000000000000..bba807840f2f4 --- /dev/null +++ b/dts/riscv/bouffalolab/bl6.dtsi @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + clock-frequency = <0>; + compatible = "riscv,sifive-e24", "riscv"; + device_type = "cpu"; + hardware-exec-breakpoint-count = <4>; + reg = <0>; + riscv,isa = "rv32imafcb"; + riscv,pmpregions = <4>; + + ictrl: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + itcm: itcm@22010000 { + compatible = "zephyr,memory-region", "sifive,dtim0"; + reg = <0x22010000 DT_SIZE_K(16)>; + zephyr,memory-region = "ITCM"; + }; + dtcm: dtcm@42014000 { + compatible = "zephyr,memory-region", "sifive,dtim0"; + reg = <0x42014000 DT_SIZE_K(48)>; + zephyr,memory-region = "DTCM"; + }; + + sram0: memory@42020000 { + compatible = "mmio-sram"; + }; + sram1: memory@42030000 { + compatible = "mmio-sram"; + reg = <0x42030000 DT_SIZE_K(112)>; + }; + + clic: clic@2000000 { + compatible = "sifive,clic"; + reg = <0x2000000 0x10000>; + reg-names = "control"; + + #interrupt-cells = <1>; + 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 */ + }; + + spi0: spi@4000a200 { + compatible = "bflb,bl-spi"; + reg = <0x4000a200 0x100>; + peripheral-id = <0>; + interrupts = <27 0>; + interrupt-parent = <&ictrl>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi1: spi@4000b000 { + compatible = "bflb,bl-qspi"; + reg = <0x4000b000 0x1000>; + peripheral-id = <0>; + interrupts = <23 0>; + interrupt-parent = <&ictrl>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; diff --git a/dts/riscv/bouffalolab/bl602.dtsi b/dts/riscv/bouffalolab/bl602.dtsi new file mode 100644 index 0000000000000..a29c538ca96f7 --- /dev/null +++ b/dts/riscv/bouffalolab/bl602.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + sram0: memory@42020000 { + reg = <0x42020000 DT_SIZE_K(64)>; + }; + }; +}; From 5318a753f8dbc760633f6af38f21a2af9d2782e1 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 2 Aug 2021 23:04:17 -0300 Subject: [PATCH 05/21] soc: riscv: bouffalolab: Add bl6 series cpu Add initial version. Signed-off-by: Gerson Fernando Budke --- modules/hal_bouffalolab/CMakeLists.txt | 2 +- modules/hal_bouffalolab/include/bflb_glb.h | 14 +++ modules/hal_bouffalolab/include/bflb_hbn.h | 14 +++ soc/bouffalolab/CMakeLists.txt | 6 + soc/bouffalolab/Kconfig | 12 ++ soc/bouffalolab/Kconfig.defconfig | 9 ++ soc/bouffalolab/Kconfig.soc | 11 ++ soc/bouffalolab/bl6/CMakeLists.txt | 10 ++ soc/bouffalolab/bl6/Kconfig | 21 ++++ soc/bouffalolab/bl6/Kconfig.defconfig | 13 +++ soc/bouffalolab/bl6/Kconfig.soc | 49 ++++++++ soc/bouffalolab/bl6/rodata.ld | 17 +++ soc/bouffalolab/bl6/soc.c | 126 +++++++++++++++++++++ soc/bouffalolab/bl6/soc.h | 49 ++++++++ soc/bouffalolab/common/CMakeLists.txt | 11 ++ soc/bouffalolab/common/clic.h | 26 +++++ soc/bouffalolab/common/soc_common.h | 82 ++++++++++++++ soc/bouffalolab/common/soc_common_irq.c | 100 ++++++++++++++++ soc/bouffalolab/common/soc_irq.S | 58 ++++++++++ soc/bouffalolab/common/vector.S | 39 +++++++ soc/bouffalolab/soc.yml | 13 +++ 21 files changed, 681 insertions(+), 1 deletion(-) create mode 100644 modules/hal_bouffalolab/include/bflb_glb.h create mode 100644 modules/hal_bouffalolab/include/bflb_hbn.h create mode 100644 soc/bouffalolab/CMakeLists.txt create mode 100644 soc/bouffalolab/Kconfig create mode 100644 soc/bouffalolab/Kconfig.defconfig create mode 100644 soc/bouffalolab/Kconfig.soc create mode 100644 soc/bouffalolab/bl6/CMakeLists.txt create mode 100644 soc/bouffalolab/bl6/Kconfig create mode 100644 soc/bouffalolab/bl6/Kconfig.defconfig create mode 100644 soc/bouffalolab/bl6/Kconfig.soc create mode 100644 soc/bouffalolab/bl6/rodata.ld create mode 100644 soc/bouffalolab/bl6/soc.c create mode 100644 soc/bouffalolab/bl6/soc.h create mode 100644 soc/bouffalolab/common/CMakeLists.txt create mode 100644 soc/bouffalolab/common/clic.h create mode 100644 soc/bouffalolab/common/soc_common.h create mode 100644 soc/bouffalolab/common/soc_common_irq.c create mode 100644 soc/bouffalolab/common/soc_irq.S create mode 100644 soc/bouffalolab/common/vector.S create mode 100644 soc/bouffalolab/soc.yml diff --git a/modules/hal_bouffalolab/CMakeLists.txt b/modules/hal_bouffalolab/CMakeLists.txt index 6f7cd0437b731..60649b8a7a298 100644 --- a/modules/hal_bouffalolab/CMakeLists.txt +++ b/modules/hal_bouffalolab/CMakeLists.txt @@ -15,7 +15,7 @@ zephyr_library_compile_definitions( BFLB_USE_CUSTOM_LD_SECTIONS ) -set(bflb_soc ${CONFIG_SOC_SUB_SERIES}) +set(bflb_soc ${CONFIG_SOC_SERIES}02) set(bflb_drv_dir ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/drivers/${bflb_soc}_driver) set(bflb_common_dir ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/common) set(bflb_drv_src_dir ${bflb_drv_dir}/std_drv/src) diff --git a/modules/hal_bouffalolab/include/bflb_glb.h b/modules/hal_bouffalolab/include/bflb_glb.h new file mode 100644 index 0000000000000..03002d8eda59c --- /dev/null +++ b/modules/hal_bouffalolab/include/bflb_glb.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_HAL_BFLB_GLB_H_ +#define ZEPHYR_HAL_BFLB_GLB_H_ + +#ifdef CONFIG_SOC_SERIES_BL6 + #include +#endif + +#endif /* ZEPHYR_HAL_BFLB_GLB_H_ */ diff --git a/modules/hal_bouffalolab/include/bflb_hbn.h b/modules/hal_bouffalolab/include/bflb_hbn.h new file mode 100644 index 0000000000000..2146f89cf5b67 --- /dev/null +++ b/modules/hal_bouffalolab/include/bflb_hbn.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_HAL_BFLB_HBN_H_ +#define ZEPHYR_HAL_BFLB_HBN_H_ + +#ifdef CONFIG_SOC_SERIES_BL6 + #include +#endif + +#endif /* ZEPHYR_HAL_BFLB_HBN_H_ */ diff --git a/soc/bouffalolab/CMakeLists.txt b/soc/bouffalolab/CMakeLists.txt new file mode 100644 index 0000000000000..613bfe0e3a474 --- /dev/null +++ b/soc/bouffalolab/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(common) +add_subdirectory(${SOC_SERIES}) diff --git a/soc/bouffalolab/Kconfig b/soc/bouffalolab/Kconfig new file mode 100644 index 0000000000000..41120b85d81c7 --- /dev/null +++ b/soc/bouffalolab/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_BFLB + select HAS_BFLB_HAL + +if SOC_FAMILY_BFLB + +rsource "*/Kconfig" + +endif # SOC_FAMILY_BFLB diff --git a/soc/bouffalolab/Kconfig.defconfig b/soc/bouffalolab/Kconfig.defconfig new file mode 100644 index 0000000000000..10203e4bd3683 --- /dev/null +++ b/soc/bouffalolab/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_BFLB + +rsource "*/Kconfig.defconfig" + +endif # SOC_FAMILY_BFLB diff --git a/soc/bouffalolab/Kconfig.soc b/soc/bouffalolab/Kconfig.soc new file mode 100644 index 0000000000000..3fc2a062c1cd5 --- /dev/null +++ b/soc/bouffalolab/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_BFLB + bool + +config SOC_FAMILY + default "bflb" if SOC_FAMILY_BFLB + +rsource "*/Kconfig.soc" diff --git a/soc/bouffalolab/bl6/CMakeLists.txt b/soc/bouffalolab/bl6/CMakeLists.txt new file mode 100644 index 0000000000000..6c3022edc1cb8 --- /dev/null +++ b/soc/bouffalolab/bl6/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +zephyr_linker_sources_ifdef(CONFIG_SOC_SERIES_BL6 RODATA rodata.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/bouffalolab/bl6/Kconfig b/soc/bouffalolab/bl6/Kconfig new file mode 100644 index 0000000000000..e147ec59b22de --- /dev/null +++ b/soc/bouffalolab/bl6/Kconfig @@ -0,0 +1,21 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL6 + select RISCV + select RISCV_HAS_CPU_IDLE + select RISCV_MACHINE_TIMER + select ATOMIC_OPERATIONS_C + select COMPRESSED_ISA + select CPU_HAS_FPU + select INCLUDE_RESET_VECTOR + select SOC_EARLY_INIT_HOOK + select XIP + + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI diff --git a/soc/bouffalolab/bl6/Kconfig.defconfig b/soc/bouffalolab/bl6/Kconfig.defconfig new file mode 100644 index 0000000000000..4b07caf0cdfb5 --- /dev/null +++ b/soc/bouffalolab/bl6/Kconfig.defconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_BL6 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 192000000 + +config NUM_IRQS + default 64 + +endif # SOC_SERIES_BL6 diff --git a/soc/bouffalolab/bl6/Kconfig.soc b/soc/bouffalolab/bl6/Kconfig.soc new file mode 100644 index 0000000000000..40c390a672bd7 --- /dev/null +++ b/soc/bouffalolab/bl6/Kconfig.soc @@ -0,0 +1,49 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL6 + bool + select SOC_FAMILY_BFLB + help + Enable support for BouffaloLab BL6xx MCU series + +config SOC_SERIES + default "bl6" if SOC_SERIES_BL6 + +config SOC_BL602C00Q2I + bool + select SOC_SERIES_BL6 + +config SOC_BL602C20Q2I + bool + select SOC_SERIES_BL6 + +config SOC_BL602C20Q2IS + bool + select SOC_SERIES_BL60X + +config SOC_BL602C40Q2IS + bool + select SOC_SERIES_BL60X + +config SOC_BL602l10Q2H + bool + select SOC_SERIES_BL60X + +config SOC_BL602l20Q2H + bool + select SOC_SERIES_BL60X + +config SOC_BL604E20Q2I + bool + select SOC_SERIES_BL6 + +config SOC + default "bl602c00q2i" if SOC_BL602C00Q2I + default "bl602c20q2i" if SOC_BL602C20Q2I + default "bl602c20q2is" if SOC_BL602C20Q2IS + default "bl602c40q2is" if SOC_BL602C40Q2IS + default "bl602l10q2h" if SOC_BL602l10Q2H + default "bl602l20q2h" if SOC_BL602l20Q2H + default "bl604e20q2i" if SOC_BL604E20Q2I diff --git a/soc/bouffalolab/bl6/rodata.ld b/soc/bouffalolab/bl6/rodata.ld new file mode 100644 index 0000000000000..fa5b54db07afe --- /dev/null +++ b/soc/bouffalolab/bl6/rodata.ld @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +KEEP(*(SORT_NONE( EXCLUDE_FILE( *bl602_glb.o \ + *bl602_pds.o \ + *bl602_common.o \ + *bl602_sf_cfg.o \ + *bl602_sf_cfg_ext*.o* \ + *bl602_sf_ctrl.o \ + *bl602_sflash.o \ + *bl602_sflash_ext*.o* \ + *bl602_xip_sflash.o \ + *bl602_xip_sflash_ext*.o* \ + *bl602_ef_ctrl.o) .rodata*))) diff --git a/soc/bouffalolab/bl6/soc.c b/soc/bouffalolab/bl6/soc.c new file mode 100644 index 0000000000000..2aadea88167c9 --- /dev/null +++ b/soc/bouffalolab/bl6/soc.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Bouffalo Lab RISC-V MCU series initialization code + */ + +#include +#include +#include + +#include +#include +#include + +/* clang-format off */ + +#define ROOT_FCLK_DIV (0) +#define ROOT_BCLK_DIV (1) +#define ROOT_UART_CLOCK_DIV (0) + +static void system_bor_init(void) +{ + HBN_BOR_CFG_Type borCfg = { 1 /* pu_bor */, 0 /* irq_bor_en */, + 1 /* bor_vth */, 1 /* bor_sel */ }; + HBN_Set_BOR_Cfg(&borCfg); +} + +static uint32_t mtimer_get_clk_src_div(void) +{ + return ((SystemCoreClockGet() / (GLB_Get_BCLK_Div() + 1)) + / 1000 / 1000 - 1); +} + +static void system_clock_init(void) +{ + GLB_Set_System_CLK(GLB_PLL_XTAL_40M, GLB_SYS_CLK_PLL160M); + GLB_Set_System_CLK_Div(ROOT_FCLK_DIV, ROOT_BCLK_DIV); + GLB_Set_MTimer_CLK(1, GLB_MTIMER_CLK_BCLK, mtimer_get_clk_src_div()); +} + +static void peripheral_clock_init(void) +{ + GLB_Set_UART_CLK(1, HBN_UART_CLK_160M, ROOT_UART_CLOCK_DIV); +} + +void soc_early_init_hook(void) +{ + uint32_t key; + uint32_t *p; + uint32_t i = 0; + uint32_t tmp = 0; + + key = irq_lock(); + + __disable_irq(); + + /* disable hardware_pullup_pull_down (reg_en_hw_pu_pd = 0) */ + tmp = BL_RD_REG(HBN_BASE, HBN_IRQ_MODE); + tmp = BL_CLR_REG_BIT(tmp, HBN_REG_EN_HW_PU_PD); + BL_WR_REG(HBN_BASE, HBN_IRQ_MODE, tmp); + + /* GLB_Set_EM_Sel(GLB_EM_0KB); */ + tmp = BL_RD_REG(GLB_BASE, GLB_SEAM_MISC); + tmp = BL_SET_REG_BITS_VAL(tmp, GLB_EM_SEL, GLB_EM_0KB); + BL_WR_REG(GLB_BASE, GLB_SEAM_MISC, tmp); + + /* Fix 26M xtal clkpll_sdmin */ + tmp = BL_RD_REG(PDS_BASE, PDS_CLKPLL_SDM); + + if (BL_GET_REG_BITS_VAL(tmp, PDS_CLKPLL_SDMIN) == 0x49D39D) { + tmp = BL_SET_REG_BITS_VAL(tmp, PDS_CLKPLL_SDMIN, 0x49D89E); + BL_WR_REG(PDS_BASE, PDS_CLKPLL_SDM, tmp); + } + + /* Restore default setting*/ + + /* GLB_UART_Sig_Swap_Set(UART_SIG_SWAP_NONE); */ + tmp = BL_RD_REG(GLB_BASE, GLB_PARM); + tmp = BL_SET_REG_BITS_VAL(tmp, GLB_UART_SWAP_SET, UART_SIG_SWAP_NONE); + BL_WR_REG(GLB_BASE, GLB_PARM, tmp); + + /* GLB_JTAG_Sig_Swap_Set(JTAG_SIG_SWAP_NONE); */ + tmp = BL_RD_REG(GLB_BASE, GLB_PARM); + tmp = BL_SET_REG_BITS_VAL(tmp, GLB_JTAG_SWAP_SET, JTAG_SIG_SWAP_NONE); + BL_WR_REG(GLB_BASE, GLB_PARM, tmp); + + /* 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(); + /* global IRQ enable */ + __enable_irq(); + + system_clock_init(); + peripheral_clock_init(); + + irq_unlock(key); +} + +/* identify flash config automatically */ +extern BL_Err_Type flash_init(void); + +void System_Post_Init(void) +{ + PDS_Trim_RC32M(); + HBN_Trim_RC32K(); + flash_init(); +} + +/* clang-format on */ diff --git a/soc/bouffalolab/bl6/soc.h b/soc/bouffalolab/bl6/soc.h new file mode 100644 index 0000000000000..a29854af2201b --- /dev/null +++ b/soc/bouffalolab/bl6/soc.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021-2024 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 +#include <../common/soc_common.h> + +#ifndef _ASMLANGUAGE + +/* Add include for DTS generated information */ +#include + +#if defined(CONFIG_SOC_SERIES_BL6) +#include +#else +#error Library does not support the specified device. +#endif + +/* clang-format off */ + +/* RISC-V Machine Timer configuration */ +#define RISCV_MTIME_BASE 0x0200BFF8 +#define RISCV_MTIMECMP_BASE 0x02004000 + +/* lib-c hooks required RAM defined variables */ +#define RISCV_RAM_BASE DT_SRAM_BASE_ADDRESS +#define RISCV_RAM_SIZE KB(DT_SRAM_SIZE) + +#define SOC_BOUFFALOLAB_BL_PLL160_FREQ_HZ (160000000) +#define SOC_BOUFFALOLAB_BL_HCLK_FREQ_HZ \ + DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) + +/* clang-format on */ + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC__H_ */ diff --git a/soc/bouffalolab/common/CMakeLists.txt b/soc/bouffalolab/common/CMakeLists.txt new file mode 100644 index 0000000000000..d080f9a230b50 --- /dev/null +++ b/soc/bouffalolab/common/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_sources( + soc_irq.S + soc_common_irq.c + vector.S + ) diff --git a/soc/bouffalolab/common/clic.h b/soc/bouffalolab/common/clic.h new file mode 100644 index 0000000000000..150146531c0dd --- /dev/null +++ b/soc/bouffalolab/common/clic.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SIFIVE_CLIC_H +#define _SIFIVE_CLIC_H + +#define CLIC_CTRL_ADDR (DT_REG_ADDR(DT_NODELABEL(clic))) +#define CLIC_HART0_OFFSET (0x800000U) +#define CLIC_HART0_ADDR (CLIC_CTRL_ADDR + CLIC_HART0_OFFSET) + +#define CLIC_MSIP 0x0000 +#define CLIC_MSIP_size 0x4 +#define CLIC_MTIMECMP 0x4000 +#define CLIC_MTIMECMP_size 0x8 +#define CLIC_MTIME 0xBFF8 +#define CLIC_MTIME_size 0x8 + +#define CLIC_INTIP 0x000 +#define CLIC_INTIE 0x400 +#define CLIC_INTCFG 0x800 +#define CLIC_CFG 0xc00 + +#endif /* _SIFIVE_CLIC_H */ diff --git a/soc/bouffalolab/common/soc_common.h b/soc/bouffalolab/common/soc_common.h new file mode 100644 index 0000000000000..532ced1721445 --- /dev/null +++ b/soc/bouffalolab/common/soc_common.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file interrupt management code for riscv SOCs supporting the SiFive clic + */ + +#ifndef __SOC_COMMON_H_ +#define __SOC_COMMON_H_ + +/* clang-format off */ + +/* IRQ numbers */ +#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ +#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ +#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ + +/* ECALL Exception numbers */ +#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ +#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ + +/* SOC-specific MCAUSE bitfields */ +#ifdef CONFIG_64BIT +/* Interrupt Mask */ +#define SOC_MCAUSE_IRQ_MASK (1 << 63) +/* Exception code Mask */ +#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFFFFFFFFFF +#else +/* Interrupt Mask */ +#define SOC_MCAUSE_IRQ_MASK (1 << 31) +/* Exception code Mask */ +#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF +#endif + +/* SOC-Specific EXIT ISR command */ +#define SOC_ERET mret + +/* CLINT Base Address */ + +#define CLIC_TIMER_ENABLE_ADDRESS (0x02800407) + +/* In mstatus register */ + +#define SOC_MIE_MSIE (0x1 << 3) /* Machine Software Interrupt Enable */ + +/* IRQ 0-15 : (exception:interrupt=0) */ + +#define SOC_IRQ_IAMISALIGNED (0) /* Instruction Address Misaligned */ +#define SOC_IRQ_IAFAULT (1) /* Instruction Address Fault */ +#define SOC_IRQ_IINSTRUCTION (2) /* Illegal Instruction */ +#define SOC_IRQ_BPOINT (3) /* Break Point */ +#define SOC_IRQ_LAMISALIGNED (4) /* Load Address Misaligned */ +#define SOC_IRQ_LAFAULT (5) /* Load Access Fault */ +#define SOC_IRQ_SAMISALIGNED (6) /* Store/AMO Address Misaligned */ +#define SOC_IRQ_SAFAULT (7) /* Store/AMO Access Fault */ +#define SOC_IRQ_ECALLU (8) /* Environment Call from U-mode */ + /* 9-10: Reserved */ +#define SOC_IRQ_ECALLM (11) /* Environment Call from M-mode */ + /* 12-15: Reserved */ + /* IRQ 16- : (async event:interrupt=1) */ +#define SOC_IRQ_NUM_BASE (16) +#define SOC_IRQ_ASYNC (16) + +/* Machine Software Int */ +#define SOC_IRQ_MSOFT (SOC_IRQ_ASYNC + RISCV_MACHINE_SOFT_IRQ) +/* Machine Timer Int */ +#define SOC_IRQ_MTIMER (SOC_IRQ_ASYNC + RISCV_MACHINE_TIMER_IRQ) +/* Machine External Int */ +#define SOC_IRQ_MEXT (SOC_IRQ_ASYNC + RISCV_MACHINE_EXT_IRQ) + +/* Machine Global External Interrupt */ +#define SOC_NR_MGEI_IRQS (64) + +/* Total number of IRQs */ +#define SOC_NR_IRQS (SOC_NR_MGEI_IRQS + SOC_IRQ_NUM_BASE) + +/* clang-format on */ + +#endif /* __SOC_COMMON_H_ */ diff --git a/soc/bouffalolab/common/soc_common_irq.c b/soc/bouffalolab/common/soc_common_irq.c new file mode 100644 index 0000000000000..38ea2e623d04c --- /dev/null +++ b/soc/bouffalolab/common/soc_common_irq.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief interrupt management code for riscv SOCs supporting the SiFive clic + */ +#include +#include +#include + +/* clang-format off */ + +static void clic_irq_enable(unsigned int irq) +{ + *(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIE + irq) = 1; +} + +static void clic_irq_disable(unsigned int irq) +{ + *(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIE + irq) = 0; +} + +void arch_irq_enable(unsigned int irq) +{ + uint32_t mie; + + if (irq == SOC_IRQ_MSOFT) { + + /* Read mstatus & set machine software interrupt enable in mie */ + + __asm__ volatile("csrrs %0, mie, %1" + : "=r"(mie) + : "r"(BIT(RISCV_MACHINE_SOFT_IRQ))); + + } else if (irq == SOC_IRQ_MTIMER) { + *(volatile uint8_t *)CLIC_TIMER_ENABLE_ADDRESS = 1; + + /* Read mstatus & set machine timer interrupt enable in mie */ + __asm__ volatile("csrrs %0, mie, %1" + : "=r"(mie) + : "r"(BIT(RISCV_MACHINE_TIMER_IRQ) + | BIT(RISCV_MACHINE_EXT_IRQ))); + } else { + clic_irq_enable(irq - SOC_IRQ_ASYNC); + } +} + +void arch_irq_disable(unsigned int irq) +{ + uint32_t mie; + + if (irq == SOC_IRQ_MSOFT) { + + /* Read mstatus & set machine software interrupt enable in mie */ + + __asm__ volatile("csrrc %0, mie, %1" + : "=r"(mie) + : "r"(BIT(RISCV_MACHINE_SOFT_IRQ))); + + } else if (irq == SOC_IRQ_MTIMER) { + *(volatile uint8_t *)CLIC_TIMER_ENABLE_ADDRESS = 0; + + /* Read mstatus & set machine timer interrupt enable in mie */ + __asm__ volatile("csrrc %0, mie, %1" + : "=r"(mie) + : "r"(BIT(RISCV_MACHINE_TIMER_IRQ) + | BIT(RISCV_MACHINE_EXT_IRQ))); + } else { + clic_irq_disable(irq - SOC_IRQ_ASYNC); + } +} + +void arch_irq_priority_set(unsigned int irq, unsigned int prio) +{ + ARG_UNUSED(irq); + ARG_UNUSED(prio); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + uint32_t mie; + + /* Enable MEIE (machine external interrupt enable) */ + __asm__ volatile("csrrs %0, mie, %1" + : "=r"(mie) + : "r"(BIT(RISCV_MACHINE_EXT_IRQ))); + + /* Read mstatus & set machine interrupt enable (MIE) in mstatus */ + __asm__ volatile("csrrs %0, mstatus, %1" + : "=r"(mie) + : "r"(MSTATUS_MIE)); + + return !!(mie & SOC_MIE_MSIE); +} + +/* clang-format on */ diff --git a/soc/bouffalolab/common/soc_irq.S b/soc/bouffalolab/common/soc_irq.S new file mode 100644 index 0000000000000..b2fabf12035c8 --- /dev/null +++ b/soc/bouffalolab/common/soc_irq.S @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * common interrupt management code for riscv SOCs supporting the riscv + * privileged architecture specification + */ +#include +#include +#include +#include +#include + +/* exports */ +GTEXT(__soc_handle_irq) + +/* + * SOC-specific function to handle pending IRQ number generating the interrupt. + * Exception number is given as parameter via register a0. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + /* Clear exception number from CSR mip register */ + li t1, 1 + sll t0, t1, a0 + csrrc t1, mip, t0 + + /* Return */ + jalr x0, ra + +/* + * __soc_is_irq is defined as .weak to allow re-implementation by + * SOCs that does not truly follow the riscv privilege specification. + */ +WTEXT(__soc_is_irq) + +/* + * SOC-specific function to determine if the exception is the result of a + * an interrupt or an exception + * return 1 (interrupt) or 0 (exception) + * + */ +SECTION_FUNC(exception.other, __soc_is_irq) + /* Read mcause and check if interrupt bit is set */ + csrr t0, mcause + li t1, SOC_MCAUSE_IRQ_MASK + and t0, t0, t1 + + /* If interrupt bit is not set, return with 0 */ + addi a0, x0, 0 + beqz t0, not_interrupt + addi a0, a0, 1 + +not_interrupt: + /* return */ + jalr x0, ra diff --git a/soc/bouffalolab/common/vector.S b/soc/bouffalolab/common/vector.S new file mode 100644 index 0000000000000..d23b9dd07c267 --- /dev/null +++ b/soc/bouffalolab/common/vector.S @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* exports */ +GTEXT(__start) + +/* imports */ +GTEXT(__initialize) +GTEXT(_isr_wrapper) + +SECTION_FUNC(vectors, __start) + .cfi_startproc + + .option norvc + + /* Inform the debugger that there is nowhere to backtrace */ + .cfi_undefined ra + + /* Disable interrupts */ + li t0, MSTATUS_MIE + csrc mstatus, t0 + + /* + * Set mtvec (Machine Trap-Vector Base-Address Register) + * CLINT Direct mode + */ + la t0, _isr_wrapper + csrw mtvec, t0 + + /* Jump to __initialize */ + tail __initialize + + .cfi_endproc diff --git a/soc/bouffalolab/soc.yml b/soc/bouffalolab/soc.yml new file mode 100644 index 0000000000000..5cedea0bb30f3 --- /dev/null +++ b/soc/bouffalolab/soc.yml @@ -0,0 +1,13 @@ +family: +- name: bouffalolab_bflb + series: + - name: bl6 + socs: + - name: bl602c00q2i + - name: bl602c20q2i + - name: bl602c20q2is + - name: bl602c40q2is + - name: bl602l10q2h + - name: bl602l20q2h + - name: bl604e20q2i +vendor: bflb From d3ac8c926785196e527a32f68fa9eb2a5b48866d Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 29 Jan 2024 22:00:59 +0100 Subject: [PATCH 06/21] soc: riscv: bouffalolab: Change to riscv-privileged Switch to use the riscv-privileged mode. Signed-off-by: Gerson Fernando Budke --- dts/riscv/bouffalolab/bl6.dtsi | 4 ++- soc/bouffalolab/bl6/Kconfig | 1 + soc/bouffalolab/bl6/Kconfig.defconfig | 8 ++++- soc/bouffalolab/common/CMakeLists.txt | 6 +++- .../common/soc_common_irq_privileged.c | 35 +++++++++++++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 soc/bouffalolab/common/soc_common_irq_privileged.c diff --git a/dts/riscv/bouffalolab/bl6.dtsi b/dts/riscv/bouffalolab/bl6.dtsi index bba807840f2f4..90e12bb445b9d 100644 --- a/dts/riscv/bouffalolab/bl6.dtsi +++ b/dts/riscv/bouffalolab/bl6.dtsi @@ -24,6 +24,7 @@ riscv,pmpregions = <4>; ictrl: interrupt-controller { + #address-cells = <0>; #interrupt-cells = <1>; compatible = "riscv,cpu-intc"; interrupt-controller; @@ -61,7 +62,8 @@ reg = <0x2000000 0x10000>; reg-names = "control"; - #interrupt-cells = <1>; + #address-cells = <0>; + #interrupt-cells = <2>; interrupt-controller; interrupts-extended = <&ictrl 3 &ictrl 7 &ictrl 11 &ictrl 12>; diff --git a/soc/bouffalolab/bl6/Kconfig b/soc/bouffalolab/bl6/Kconfig index e147ec59b22de..1a052905eb080 100644 --- a/soc/bouffalolab/bl6/Kconfig +++ b/soc/bouffalolab/bl6/Kconfig @@ -6,6 +6,7 @@ config SOC_SERIES_BL6 select RISCV select RISCV_HAS_CPU_IDLE select RISCV_MACHINE_TIMER + select RISCV_PRIVILEGED select ATOMIC_OPERATIONS_C select COMPRESSED_ISA select CPU_HAS_FPU diff --git a/soc/bouffalolab/bl6/Kconfig.defconfig b/soc/bouffalolab/bl6/Kconfig.defconfig index 4b07caf0cdfb5..a9c2a820aa3a0 100644 --- a/soc/bouffalolab/bl6/Kconfig.defconfig +++ b/soc/bouffalolab/bl6/Kconfig.defconfig @@ -8,6 +8,12 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC default 192000000 config NUM_IRQS - default 64 + default 80 + +config RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET + default 0 + +config RISCV_TRAP_HANDLER_ALIGNMENT + default 8 endif # SOC_SERIES_BL6 diff --git a/soc/bouffalolab/common/CMakeLists.txt b/soc/bouffalolab/common/CMakeLists.txt index d080f9a230b50..a3bc7c9e57125 100644 --- a/soc/bouffalolab/common/CMakeLists.txt +++ b/soc/bouffalolab/common/CMakeLists.txt @@ -4,7 +4,11 @@ zephyr_include_directories(.) -zephyr_sources( +zephyr_sources_ifdef(CONFIG_RISCV_PRIVILEGED + soc_common_irq_privileged.c + ) + +zephyr_sources_ifndef(CONFIG_RISCV_PRIVILEGED soc_irq.S soc_common_irq.c vector.S diff --git a/soc/bouffalolab/common/soc_common_irq_privileged.c b/soc/bouffalolab/common/soc_common_irq_privileged.c new file mode 100644 index 0000000000000..3571353c64b68 --- /dev/null +++ b/soc/bouffalolab/common/soc_common_irq_privileged.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief interrupt management code for riscv SOCs supporting the SiFive clic + */ +#include +#include +#include + +void riscv_clic_irq_enable(unsigned int irq) +{ + sys_write8(1, CLIC_HART0_ADDR + CLIC_INTIE + irq); +} + +void riscv_clic_irq_disable(unsigned int irq) +{ + sys_write8(0, CLIC_HART0_ADDR + CLIC_INTIE + irq); +} + +void riscv_clic_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) +{ + ARG_UNUSED(irq); + ARG_UNUSED(prio); + ARG_UNUSED(flags); +} + +int riscv_clic_irq_is_enabled(unsigned int irq) +{ + return sys_read8(CLIC_HART0_ADDR + CLIC_INTIE + irq); +} From ba4daeba227e82a2513008d219c625a90961a8e5 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sat, 27 Jan 2024 10:54:29 +0100 Subject: [PATCH 07/21] drivers: pinctrl: bouffalolab: Add bflb pinctrl driver Add Bouffalo Lab pinctrl driver. Signed-off-by: Gerson Fernando Budke --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.bflb | 10 ++ drivers/pinctrl/pinctrl_bflb.c | 45 +++++++++ dts/bindings/gpio/bflb,bl-gpio.yaml | 35 +++++++ dts/bindings/pinctrl/bflb,bl-pinctrl.yaml | 91 +++++++++++++++++++ dts/riscv/bouffalolab/bl6.dtsi | 22 +++++ .../drivers/pinctrl/pinctrl_soc_bflb_common.h | 82 +++++++++++++++++ modules/hal_bouffalolab/include/bflb_gpio.h | 14 +++ .../hal_bouffalolab/include/bflb_pinctrl.h | 15 +++ soc/bouffalolab/common/pinctrl_soc.h | 17 ++++ 11 files changed, 333 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.bflb create mode 100644 drivers/pinctrl/pinctrl_bflb.c create mode 100644 dts/bindings/gpio/bflb,bl-gpio.yaml create mode 100644 dts/bindings/pinctrl/bflb,bl-pinctrl.yaml create mode 100644 include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h create mode 100644 modules/hal_bouffalolab/include/bflb_gpio.h create mode 100644 modules/hal_bouffalolab/include/bflb_pinctrl.h create mode 100644 soc/bouffalolab/common/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index d2834504eb2e0..930e489565170 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_library() zephyr_library_sources(common.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TELINK_B91 pinctrl_b91.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_AMBIQ pinctrl_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_BFLB pinctrl_bflb.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AFIO pinctrl_gd32_afio.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_ITE_IT8XXX2 pinctrl_ite_it8xxx2.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d8621e7ad9e1d..844ec3c98ff96 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -34,6 +34,7 @@ config PINCTRL_DYNAMIC peripheral at early boot stages depending on a certain input. source "drivers/pinctrl/Kconfig.b91" +source "drivers/pinctrl/Kconfig.bflb" source "drivers/pinctrl/Kconfig.ambiq" source "drivers/pinctrl/Kconfig.gd32" source "drivers/pinctrl/Kconfig.it8xxx2" diff --git a/drivers/pinctrl/Kconfig.bflb b/drivers/pinctrl/Kconfig.bflb new file mode 100644 index 0000000000000..b98ad37915c04 --- /dev/null +++ b/drivers/pinctrl/Kconfig.bflb @@ -0,0 +1,10 @@ +# Copyright (c) 2021-2024 Gerson Fernando Budke +# +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_BFLB + bool "Bouffalo Lab pin control driver" + depends on DT_HAS_BFLB_BL_PINCTRL_ENABLED + default y + help + Bouffalo Lab pin control driver diff --git a/drivers/pinctrl/pinctrl_bflb.c b/drivers/pinctrl/pinctrl_bflb.c new file mode 100644 index 0000000000000..2848e1dd5cc62 --- /dev/null +++ b/drivers/pinctrl/pinctrl_bflb.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/* clang-format off */ + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, + uintptr_t reg) +{ + GLB_GPIO_Cfg_Type pincfg; + uint8_t i; + + ARG_UNUSED(reg); + + for (i = 0U; i < pin_cnt; i++) { + pincfg.gpioFun = BFLB_PINMUX_GET_FUN(pins[i]); + pincfg.gpioMode = BFLB_PINMUX_GET_MODE(pins[i]); + pincfg.gpioPin = BFLB_PINMUX_GET_PIN(pins[i]); + pincfg.pullType = BFLB_PINMUX_GET_PULL_MODES(pins[i]); + pincfg.smtCtrl = BFLB_PINMUX_GET_SMT(pins[i]); + pincfg.drive = BFLB_PINMUX_GET_DRIVER_STRENGTH(pins[i]); + + if (pincfg.gpioFun == BFLB_PINMUX_FUN_INST_uart0) { + GLB_UART_Fun_Sel(pincfg.gpioPin % 8, + (BFLB_PINMUX_GET_INST(pins[i])) + * 0x4U /* rts, cts, rx, tx */ + + BFLB_PINMUX_GET_SIGNAL(pins[i]) + ); + } + + GLB_GPIO_Init(&pincfg); + } + + return 0; +} + +/* clang-format on */ diff --git a/dts/bindings/gpio/bflb,bl-gpio.yaml b/dts/bindings/gpio/bflb,bl-gpio.yaml new file mode 100644 index 0000000000000..960eae5d8e17a --- /dev/null +++ b/dts/bindings/gpio/bflb,bl-gpio.yaml @@ -0,0 +1,35 @@ +# Copyright (c) 2021-2024 Gerson Fernando Budke +# +# SPDX-License-Identifier: Apache-2.0 + +description: Bouffalo Lab GPIO node + +compatible: "bflb,bl-gpio" + +include: + - name: base.yaml + - name: gpio-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + "#gpio-cells": + const: 2 + + "#bflb,pin-cells": + type: int + required: true + const: 2 + description: Number of items to expect in a bflb,pins specifier + +gpio-cells: + - pin + - flags + +bflb,pin-cells: + - pin + - peripheral diff --git a/dts/bindings/pinctrl/bflb,bl-pinctrl.yaml b/dts/bindings/pinctrl/bflb,bl-pinctrl.yaml new file mode 100644 index 0000000000000..d297065bc57f3 --- /dev/null +++ b/dts/bindings/pinctrl/bflb,bl-pinctrl.yaml @@ -0,0 +1,91 @@ +# Copyright (c) 2021-2024 Gerson Fernando Budke +# +# SPDX-License-Identifier: Apache-2.0 + +description: Bouffalo Lab Pinctrl node + +compatible: "bflb,bl-pinctrl" + +include: base.yaml + +properties: + "#address-cells": + required: true + const: 1 + "#size-cells": + required: true + const: 1 + +child-binding: + description: | + Bouffalo Lab pin controller pin configuration nodes. Each node is composed + by one or more groups, each defining the configuration for a set of pins. + + child-binding: + description: | + Bouffalo Lab pin controller pin configuration group. Each group contains + a list of pins sharing the same set of properties. Example: + + uart0_default: uart0_default { + /* group 1 (name is arbitrary) */ + group1 { + /* configure to uart0 function plus modem interrupt, pin 7 as UART_RX + pin 16 as UART_TX and finally pin 18 as gpio */ + pinmux = , + ; + bias-pull-up; + input-schmitt-enable; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + pinmux = , + ; + bias-high-impedance; + }; + }; + + The list of supported standard properties: + - bias-high-impedance: Disable pull-up/down (default behavior, not + required). + - bias-pull-up: Enable pull-up resistor. + - bias-pull-down: Enable pull-down resistor. + - input-enable: Enable GPIO as input (default behavior, not required). + - input-schmitt-enable: Enable Schimitt Trigger when GPIO is Input. + - output-enable: Enable GPIO as output. + + Note that bias options are mutually exclusive. It is the same with GPIO + input/output enable options. + + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-high-impedance + - bias-pull-down + - bias-pull-up + - input-enable + - input-schmitt-enable + - output-enable + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. The pins should be + defined using the BFLB_PINMUX utility macro that encode all the pin + route matrix. + drive-strength: + type: int + default: 0 + enum: + - 0 # Default value, lower strength, 8mA + - 1 # 9.6mA + - 2 # 11.2mA + - 3 # highest strength, 12.8mA + description: | + Pin drive strength. It tunes pin max current where 0 means lower + value, which is the default, and 3 represents max drive strength. + The driver will automatically apply the default value (8mA) to all + pins to save power. diff --git a/dts/riscv/bouffalolab/bl6.dtsi b/dts/riscv/bouffalolab/bl6.dtsi index 90e12bb445b9d..db1fe82b842f5 100644 --- a/dts/riscv/bouffalolab/bl6.dtsi +++ b/dts/riscv/bouffalolab/bl6.dtsi @@ -5,6 +5,8 @@ */ #include +#include +#include / { #address-cells = <1>; @@ -73,6 +75,26 @@ "csip"; /* CLIC Software Interrupt */ }; + pinctrl: pin-controller@40000000 { + compatible = "bflb,bl-pinctrl"; + reg = <0x40000000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0x1000>; + status = "okay"; + + glb: gpio@40000000 { + compatible = "bflb,bl-gpio"; + reg = <0x40000000 0x1000>; + interrupts = <1 0>; + interrupt-parent = <&ictrl>; + gpio-controller; + #gpio-cells = <2>; + #bflb,pin-cells = <2>; + status = "disabled"; + }; + }; + spi0: spi@4000a200 { compatible = "bflb,bl-spi"; reg = <0x4000a200 0x100>; diff --git a/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h b/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h new file mode 100644 index 0000000000000..6bc371a9b0af4 --- /dev/null +++ b/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * Bouffalo Lab SoC specific helpers for pinctrl driver + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_PINCTRL_PINCTRL_SOC_BFLB_COMMON_H_ +#define ZEPHYR_INCLUDE_DRIVERS_PINCTRL_PINCTRL_SOC_BFLB_COMMON_H_ + +#include +#include + +/* clang-format off */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief BFLB pincfg bit field. + * @anchor BFLB_PINMUX + * + * Fields: + * + * - 24..31: pin + * - 20..23: signal + * - 18..19: mode + * - 16..17: instance + * - 8..15: function + * - 7: reserved + * - 6: GPIO Output Enable + * - 5: Pull Down + * - 4: Pull Up + * - 2..3: Driver Strength + * - 1: Schmitt trigger (SMT) + * - 0: reserved + */ +typedef uint32_t pinctrl_soc_pin_t; + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param prop Property name. + * @param idx Property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + ((DT_PROP_BY_IDX(node_id, prop, idx)) \ + | (DT_PROP(node_id, bias_pull_up) << BFLB_PINMUX_PULL_UP_POS) \ + | (DT_PROP(node_id, bias_pull_down) << BFLB_PINMUX_PULL_DOWN_POS) \ + | (DT_PROP(node_id, output_enable) << BFLB_PINMUX_OE_POS) \ + | (DT_PROP(node_id, input_schmitt_enable) << BFLB_PINMUX_SMT_POS) \ + | (DT_ENUM_IDX(node_id, drive_strength) << BFLB_PINMUX_DRIVER_STRENGTH_POS) \ + ), + +/** + * @brief Utility macro to initialize state pins contained in a given property. + * + * @param node_id Node identifier. + * @param prop Property name describing state pins. + */ +#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)} + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +/* clang-format on */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_PINCTRL_PINCTRL_SOC_BFLB_COMMON_H_ */ diff --git a/modules/hal_bouffalolab/include/bflb_gpio.h b/modules/hal_bouffalolab/include/bflb_gpio.h new file mode 100644 index 0000000000000..ed89a4532abbc --- /dev/null +++ b/modules/hal_bouffalolab/include/bflb_gpio.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_HAL_BFLB_GPIO_H_ +#define ZEPHYR_HAL_BFLB_GPIO_H_ + +#ifdef CONFIG_SOC_SERIES_BL6 + #include +#endif + +#endif /* ZEPHYR_HAL_BFLB_GPIO_H_ */ diff --git a/modules/hal_bouffalolab/include/bflb_pinctrl.h b/modules/hal_bouffalolab/include/bflb_pinctrl.h new file mode 100644 index 0000000000000..848c2862f70e4 --- /dev/null +++ b/modules/hal_bouffalolab/include/bflb_pinctrl.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_HAL_BFLB_PINCTRL_H_ +#define ZEPHYR_HAL_BFLB_PINCTRL_H_ + +#ifdef CONFIG_SOC_SERIES_BL6 +# include +#endif +#include + +#endif /* ZEPHYR_HAL_BFLB_PINCTRL_H_ */ diff --git a/soc/bouffalolab/common/pinctrl_soc.h b/soc/bouffalolab/common/pinctrl_soc.h new file mode 100644 index 0000000000000..39ab88acd9141 --- /dev/null +++ b/soc/bouffalolab/common/pinctrl_soc.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * Bouffalo Lab SoC specific helpers for pinctrl driver + */ + +#ifndef ZEPHYR_SOC_RISCV_BFLB_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_RISCV_BFLB_COMMON_PINCTRL_SOC_H_ + +#include + +#endif /* ZEPHYR_SOC_RISCV_BFLB_COMMON_PINCTRL_SOC_H_ */ From 784efc14a20f1317e74a4bbf9d44228b78673579 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 2 Aug 2021 23:07:11 -0300 Subject: [PATCH 08/21] drivers: serial: bouffalolab: Add bflb serial driver Add Bouffalo Lab serial driver. The driver uses pinctrl to configure pins and have power management capabilities. Signed-off-by: Gerson Fernando Budke --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.bflb | 12 ++ drivers/serial/uart_bflb.c | 127 ++++++++++++++++++++ dts/bindings/serial/bflb,bl-uart.yaml | 20 +++ dts/riscv/bouffalolab/bl6.dtsi | 17 +++ modules/hal_bouffalolab/include/bflb_uart.h | 14 +++ 7 files changed, 193 insertions(+) create mode 100644 drivers/serial/Kconfig.bflb create mode 100644 drivers/serial/uart_bflb.c create mode 100644 dts/bindings/serial/bflb,bl-uart.yaml create mode 100644 modules/hal_bouffalolab/include/bflb_uart.h diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index c3b1f8acdd91a..28b00352e112a 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -18,6 +18,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_ALTERA uart_altera.c) zephyr_library_sources_ifdef(CONFIG_UART_ALTERA_JTAG uart_altera_jtag.c) zephyr_library_sources_ifdef(CONFIG_UART_APBUART uart_apbuart.c) zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c) +zephyr_library_sources_ifdef(CONFIG_UART_BFLB uart_bflb.c) zephyr_library_sources_ifdef(CONFIG_UART_BT uart_bt.c) zephyr_library_sources_ifdef(CONFIG_UART_CC13XX_CC26XX uart_cc13xx_cc26xx.c) zephyr_library_sources_ifdef(CONFIG_UART_CC32XX uart_cc32xx.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 013f0343bd776..2e1e802bb4cff 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -220,6 +220,8 @@ rsource "Kconfig.xlnx" rsource "Kconfig.xmc4xxx" # zephyr-keep-sorted-stop +rsource "Kconfig.bflb" + source "drivers/serial/Kconfig.si32" source "drivers/serial/Kconfig.wch_usart" diff --git a/drivers/serial/Kconfig.bflb b/drivers/serial/Kconfig.bflb new file mode 100644 index 0000000000000..c65bd53575f99 --- /dev/null +++ b/drivers/serial/Kconfig.bflb @@ -0,0 +1,12 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +config UART_BFLB + bool "Bouffalo Lab serial driver" + depends on DT_HAS_BFLB_BL_UART_ENABLED + select PINCTRL + select SERIAL_HAS_DRIVER + select USE_BFLB_UART + help + This option enables the UART driver for Bouffalo Lab SoC family. diff --git a/drivers/serial/uart_bflb.c b/drivers/serial/uart_bflb.c new file mode 100644 index 0000000000000..6efbf0c26f0e7 --- /dev/null +++ b/drivers/serial/uart_bflb.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bflb_bl_uart + +/** + * @brief UART driver for Bouffalo Lab MCU family. + */ +#include +#include +#include +#include +#include +#include + +#define UART_CTS_FLOWCONTROL_ENABLE (0) +#define UART_RTS_FLOWCONTROL_ENABLE (0) +#define UART_MSB_FIRST_ENABLE (0) +#define UART_DEFAULT_RTO_TIMEOUT (255) +#define UART_CLOCK_DIV (0) + +struct bl_config { + const struct pinctrl_dev_config *pinctrl_cfg; + uint32_t periph_id; + UART_CFG_Type uart_cfg; + UART_FifoCfg_Type fifo_cfg; +}; + +static int uart_bl_init(const struct device *dev) +{ + const struct bl_config *cfg = dev->config; + + pinctrl_apply_state(cfg->pinctrl_cfg, PINCTRL_STATE_DEFAULT); + + GLB_Set_UART_CLK(1, HBN_UART_CLK_160M, UART_CLOCK_DIV); + + UART_IntMask(cfg->periph_id, UART_INT_ALL, 1); + UART_Disable(cfg->periph_id, UART_TXRX); + + UART_Init(cfg->periph_id, (UART_CFG_Type *)&cfg->uart_cfg); + UART_TxFreeRun(cfg->periph_id, 1); + UART_SetRxTimeoutValue(cfg->periph_id, UART_DEFAULT_RTO_TIMEOUT); + UART_FifoConfig(cfg->periph_id, (UART_FifoCfg_Type *)&cfg->fifo_cfg); + UART_Enable(cfg->periph_id, UART_TXRX); + + return 0; +} + +static int uart_bl_poll_in(const struct device *dev, unsigned char *c) +{ + const struct bl_config *cfg = dev->config; + + return UART_ReceiveData(cfg->periph_id, (uint8_t *)c, 1) ? 0 : -1; +} + +static void uart_bl_poll_out(const struct device *dev, unsigned char c) +{ + const struct bl_config *cfg = dev->config; + + while (UART_GetTxFifoCount(cfg->periph_id) == 0) { + ; + } + + (void)UART_SendData(cfg->periph_id, (uint8_t *)&c, 1); +} + +#ifdef CONFIG_PM_DEVICE +static int uart_bl_pm_control(const struct device *dev, + enum pm_device_action action) +{ + const struct bl_config *cfg = dev->config; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + (void)pinctrl_apply_state(cfg->pinctrl_cfg, PINCTRL_STATE_DEFAULT); + UART_Enable(cfg->periph_id, UART_TXRX); + break; + case PM_DEVICE_ACTION_SUSPEND: + if (pinctrl_apply_state(cfg->pinctrl_cfg, PINCTRL_STATE_SLEEP)) { + return -ENOTSUP; + } + UART_Disable(cfg->periph_id, UART_TXRX); + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ + +static const struct uart_driver_api uart_bl_driver_api = { + .poll_in = uart_bl_poll_in, + .poll_out = uart_bl_poll_out, +}; + +#define BL_UART_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static const struct bl_config bl_uart##n##_config = { \ + .pinctrl_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .periph_id = DT_INST_PROP(n, peripheral_id), \ + \ + .uart_cfg.baudRate = DT_INST_PROP(n, current_speed), \ + .uart_cfg.dataBits = UART_DATABITS_8, \ + .uart_cfg.stopBits = UART_STOPBITS_1, \ + .uart_cfg.parity = UART_PARITY_NONE, \ + .uart_cfg.uartClk = SOC_BOUFFALOLAB_BL_PLL160_FREQ_HZ, \ + .uart_cfg.ctsFlowControl = UART_CTS_FLOWCONTROL_ENABLE, \ + .uart_cfg.rtsSoftwareControl = UART_RTS_FLOWCONTROL_ENABLE, \ + .uart_cfg.byteBitInverse = UART_MSB_FIRST_ENABLE, \ + \ + .fifo_cfg.txFifoDmaThreshold = 1, \ + .fifo_cfg.rxFifoDmaThreshold = 1, \ + .fifo_cfg.txFifoDmaEnable = 0, \ + .fifo_cfg.rxFifoDmaEnable = 0, \ + }; \ + DEVICE_DT_INST_DEFINE(n, &uart_bl_init, \ + uart_bl_pm_control, \ + NULL, \ + &bl_uart##n##_config, PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_bl_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(BL_UART_INIT) diff --git a/dts/bindings/serial/bflb,bl-uart.yaml b/dts/bindings/serial/bflb,bl-uart.yaml new file mode 100644 index 0000000000000..8e2c67ea208c5 --- /dev/null +++ b/dts/bindings/serial/bflb,bl-uart.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +description: Bouffalo Lab UART + +compatible: "bflb,bl-uart" + +include: + - name: uart-controller.yaml + - name: pinctrl-device.yaml + +properties: + reg: + required: true + + peripheral-id: + type: int + description: peripheral ID + required: true diff --git a/dts/riscv/bouffalolab/bl6.dtsi b/dts/riscv/bouffalolab/bl6.dtsi index db1fe82b842f5..e8ebcce4e455b 100644 --- a/dts/riscv/bouffalolab/bl6.dtsi +++ b/dts/riscv/bouffalolab/bl6.dtsi @@ -116,5 +116,22 @@ #address-cells = <1>; #size-cells = <0>; }; + + uart0: uart@4000a000 { + compatible = "bflb,bl-uart"; + reg = <0x4000a000 0x100>; + peripheral-id = <0>; + interrupts = <29 0>; + interrupt-parent = <&ictrl>; + status = "disabled"; + }; + uart1: uart@4000a100 { + compatible = "bflb,bl-uart"; + reg = <0x4000a100 0x100>; + peripheral-id = <1>; + interrupts = <30 0>; + interrupt-parent = <&ictrl>; + status = "disabled"; + }; }; }; diff --git a/modules/hal_bouffalolab/include/bflb_uart.h b/modules/hal_bouffalolab/include/bflb_uart.h new file mode 100644 index 0000000000000..903f11c9c4f74 --- /dev/null +++ b/modules/hal_bouffalolab/include/bflb_uart.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_HAL_BFLB_UART_H_ +#define ZEPHYR_HAL_BFLB_UART_H_ + +#ifdef CONFIG_SOC_SERIES_BL6 + #include +#endif + +#endif /* ZEPHYR_HAL_BFLB_UART_H_ */ From df8f88daaee8c5cb1eed0716e42a5b32d928bab9 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Wed, 10 Nov 2021 23:13:25 -0300 Subject: [PATCH 09/21] drivers: serial: bouffalolab: Add support to interrupts Enable interrupt support in the driver. Signed-off-by: Gerson Fernando Budke --- drivers/serial/Kconfig.bflb | 1 + drivers/serial/uart_bflb.c | 248 ++++++++++++++++++++++++++++++++++-- 2 files changed, 238 insertions(+), 11 deletions(-) diff --git a/drivers/serial/Kconfig.bflb b/drivers/serial/Kconfig.bflb index c65bd53575f99..d619792f99e32 100644 --- a/drivers/serial/Kconfig.bflb +++ b/drivers/serial/Kconfig.bflb @@ -7,6 +7,7 @@ config UART_BFLB depends on DT_HAS_BFLB_BL_UART_ENABLED select PINCTRL select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT select USE_BFLB_UART help This option enables the UART driver for Bouffalo Lab SoC family. diff --git a/drivers/serial/uart_bflb.c b/drivers/serial/uart_bflb.c index 6efbf0c26f0e7..4cd1a4d67906b 100644 --- a/drivers/serial/uart_bflb.c +++ b/drivers/serial/uart_bflb.c @@ -11,6 +11,7 @@ */ #include #include +#include #include #include #include @@ -22,16 +23,27 @@ #define UART_DEFAULT_RTO_TIMEOUT (255) #define UART_CLOCK_DIV (0) -struct bl_config { +struct bflb_config { + uint32_t *reg; const struct pinctrl_dev_config *pinctrl_cfg; uint32_t periph_id; UART_CFG_Type uart_cfg; UART_FifoCfg_Type fifo_cfg; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_config_func_t irq_config_func; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +struct bflb_data { +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t user_cb; + void *user_data; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; static int uart_bl_init(const struct device *dev) { - const struct bl_config *cfg = dev->config; + const struct bflb_config *cfg = dev->config; pinctrl_apply_state(cfg->pinctrl_cfg, PINCTRL_STATE_DEFAULT); @@ -46,19 +58,23 @@ static int uart_bl_init(const struct device *dev) UART_FifoConfig(cfg->periph_id, (UART_FifoCfg_Type *)&cfg->fifo_cfg); UART_Enable(cfg->periph_id, UART_TXRX); +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + cfg->irq_config_func(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + return 0; } static int uart_bl_poll_in(const struct device *dev, unsigned char *c) { - const struct bl_config *cfg = dev->config; + const struct bflb_config *cfg = dev->config; return UART_ReceiveData(cfg->periph_id, (uint8_t *)c, 1) ? 0 : -1; } static void uart_bl_poll_out(const struct device *dev, unsigned char c) { - const struct bl_config *cfg = dev->config; + const struct bflb_config *cfg = dev->config; while (UART_GetTxFifoCount(cfg->periph_id) == 0) { ; @@ -67,11 +83,174 @@ static void uart_bl_poll_out(const struct device *dev, unsigned char c) (void)UART_SendData(cfg->periph_id, (uint8_t *)&c, 1); } +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static int uart_bl_err_check(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t status = BL_RD_REG(cfg->reg, UART_INT_STS); + uint32_t tmp = BL_RD_REG(cfg->reg, UART_INT_CLEAR); + int errors = 0; + + if (status & BIT(UART_INT_RX_FER)) { + tmp |= BIT(UART_INT_RX_FER); + + errors |= UART_ERROR_OVERRUN; + } + + if (status & BIT(UART_INT_TX_FER)) { + tmp |= BIT(UART_INT_TX_FER); + + errors |= UART_ERROR_OVERRUN; + } + + if (status & BIT(UART_INT_PCE)) { + tmp |= BIT(UART_INT_PCE); + + errors |= UART_ERROR_PARITY; + } + + BL_WR_REG(cfg->reg, UART_INT_CLEAR, tmp); + + return errors; +} + +int uart_bl_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) +{ + const struct bflb_config *const cfg = dev->config; + uint8_t num_tx = 0U; + + while ((len - num_tx > 0) && (UART_GetTxFifoCount(cfg->periph_id) > 0)) { + BL_WR_BYTE(cfg->reg + UART_FIFO_WDATA_OFFSET, tx_data[num_tx++]); + } + + return num_tx; +} + +int uart_bl_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + const struct bflb_config *const cfg = dev->config; + uint8_t num_rx = 0U; + + while ((size - num_rx > 0) && (UART_GetRxFifoCount(cfg->periph_id) > 0)) { + rx_data[num_rx++] = BL_RD_BYTE(cfg->reg + UART_FIFO_RDATA_OFFSET); + } + + return num_rx; +} + +void uart_bl_irq_tx_enable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + UART_IntMask(cfg->periph_id, UART_INT_TX_FIFO_REQ, 1); +} + +void uart_bl_irq_tx_disable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + UART_IntMask(cfg->periph_id, UART_INT_TX_FIFO_REQ, 0); +} + +int uart_bl_irq_tx_ready(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t maskVal = BL_RD_REG(cfg->reg, UART_INT_MASK); + + return (UART_GetTxFifoCount(cfg->periph_id) > 0) + && BL_IS_REG_BIT_SET(maskVal, UART_CR_UTX_FIFO_MASK); +} + +int uart_bl_irq_tx_complete(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + return !UART_GetTxBusBusyStatus(cfg->periph_id); +} + +void uart_bl_irq_rx_enable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + UART_IntMask(cfg->periph_id, UART_INT_RX_FIFO_REQ, 1); +} + +void uart_bl_irq_rx_disable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + UART_IntMask(cfg->periph_id, UART_INT_RX_FIFO_REQ, 0); +} + +int uart_bl_irq_rx_ready(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + return UART_GetRxFifoCount(cfg->periph_id) > 0; +} + +void uart_bl_irq_err_enable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + UART_IntMask(cfg->periph_id, UART_INT_PCE + | UART_INT_TX_FER + | UART_INT_RX_FER, 1); +} + +void uart_bl_irq_err_disable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + + UART_IntMask(cfg->periph_id, UART_INT_PCE + | UART_INT_TX_FER + | UART_INT_RX_FER, 0); +} + +int uart_bl_irq_is_pending(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = BL_RD_REG(cfg->reg, UART_INT_STS); + uint32_t maskVal = BL_RD_REG(cfg->reg, UART_INT_MASK); + + return ((BL_IS_REG_BIT_SET(tmp, UART_URX_FIFO_INT) && + BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_FIFO_MASK)) || + (BL_IS_REG_BIT_SET(tmp, UART_UTX_FIFO_INT) && + BL_IS_REG_BIT_SET(maskVal, UART_CR_UTX_FIFO_MASK))); +} + +int uart_bl_irq_update(const struct device *dev) +{ + ARG_UNUSED(dev); + + return 1; +} + +void uart_bl_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct bflb_data *const data = dev->data; + + data->user_cb = cb; + data->user_data = user_data; +} + +static void uart_bl_isr(const struct device *dev) +{ + struct bflb_data *const data = dev->data; + + if (data->user_cb) { + data->user_cb(dev, data->user_data); + } +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + #ifdef CONFIG_PM_DEVICE static int uart_bl_pm_control(const struct device *dev, enum pm_device_action action) { - const struct bl_config *cfg = dev->config; + const struct bflb_config *cfg = dev->config; switch (action) { case PM_DEVICE_ACTION_RESUME: @@ -95,11 +274,54 @@ static int uart_bl_pm_control(const struct device *dev, static const struct uart_driver_api uart_bl_driver_api = { .poll_in = uart_bl_poll_in, .poll_out = uart_bl_poll_out, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .err_check = uart_bl_err_check, + .fifo_fill = uart_bl_fifo_fill, + .fifo_read = uart_bl_fifo_read, + .irq_tx_enable = uart_bl_irq_tx_enable, + .irq_tx_disable = uart_bl_irq_tx_disable, + .irq_tx_ready = uart_bl_irq_tx_ready, + .irq_tx_complete = uart_bl_irq_tx_complete, + .irq_rx_enable = uart_bl_irq_rx_enable, + .irq_rx_disable = uart_bl_irq_rx_disable, + .irq_rx_ready = uart_bl_irq_rx_ready, + .irq_err_enable = uart_bl_irq_err_enable, + .irq_err_disable = uart_bl_irq_err_disable, + .irq_is_pending = uart_bl_irq_is_pending, + .irq_update = uart_bl_irq_update, + .irq_callback_set = uart_bl_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; -#define BL_UART_INIT(n) \ +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define BFLB_UART_IRQ_HANDLER_DECL(n) \ + static void uart_bl_config_func_##n(const struct device *dev); +#define BFLB_UART_IRQ_HANDLER_FUNC(n) \ + .irq_config_func = uart_bl_config_func_##n +#define BFLB_UART_IRQ_HANDLER(n) \ + static void uart_bl_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + uart_bl_isr, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } +#else /* CONFIG_UART_INTERRUPT_DRIVEN */ +#define BFLB_UART_IRQ_HANDLER_DECL(n) +#define BFLB_UART_IRQ_HANDLER_FUNC(n) +#define BFLB_UART_IRQ_HANDLER(n) +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#define BFLB_UART_INIT(n) \ PINCTRL_DT_INST_DEFINE(n); \ - static const struct bl_config bl_uart##n##_config = { \ + \ + BFLB_UART_IRQ_HANDLER_DECL(n) \ + \ + static struct bflb_data uart##n##_bl_data; \ + static const struct bflb_config uart##n##_bl_config = { \ + .reg = (uint32_t *)DT_INST_REG_ADDR(n), \ .pinctrl_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .periph_id = DT_INST_PROP(n, peripheral_id), \ \ @@ -116,12 +338,16 @@ static const struct uart_driver_api uart_bl_driver_api = { .fifo_cfg.rxFifoDmaThreshold = 1, \ .fifo_cfg.txFifoDmaEnable = 0, \ .fifo_cfg.rxFifoDmaEnable = 0, \ + \ + BFLB_UART_IRQ_HANDLER_FUNC(n) \ }; \ DEVICE_DT_INST_DEFINE(n, &uart_bl_init, \ uart_bl_pm_control, \ - NULL, \ - &bl_uart##n##_config, PRE_KERNEL_1, \ + &uart##n##_bl_data, \ + &uart##n##_bl_config, PRE_KERNEL_1, \ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ - &uart_bl_driver_api); + &uart_bl_driver_api); \ + \ + BFLB_UART_IRQ_HANDLER(n) -DT_INST_FOREACH_STATUS_OKAY(BL_UART_INIT) +DT_INST_FOREACH_STATUS_OKAY(BFLB_UART_INIT) From b20d5ad44205aab60614d046ab30f02eb11f5a83 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sat, 7 Aug 2021 15:04:13 -0300 Subject: [PATCH 10/21] scripts: runner: Introduce blflash runner Add Bouffalo Lab ISP console flash runner. This tool enable bootloader to flash devices using serial port. The blflash Rust tool can be found at https://github.com/spacemeowx2/blflash Signed-off-by: Gerson Fernando Budke --- boards/common/blflash.board.cmake | 4 ++ scripts/west_commands/runners/__init__.py | 1 + scripts/west_commands/runners/blflash.py | 59 +++++++++++++++++++++ scripts/west_commands/tests/test_imports.py | 1 + 4 files changed, 65 insertions(+) create mode 100644 boards/common/blflash.board.cmake create mode 100644 scripts/west_commands/runners/blflash.py diff --git a/boards/common/blflash.board.cmake b/boards/common/blflash.board.cmake new file mode 100644 index 0000000000000..5c99a2b913bf1 --- /dev/null +++ b/boards/common/blflash.board.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(blflash) +board_finalize_runner_args(blflash) diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index 3ed333c24c28e..cd7be7f92d0fc 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -27,6 +27,7 @@ def _import_runner_module(runner_name): _names = [ # zephyr-keep-sorted-start 'blackmagicprobe', + 'blflash', 'bossac', 'canopen_program', 'dediprog', diff --git a/scripts/west_commands/runners/blflash.py b/scripts/west_commands/runners/blflash.py new file mode 100644 index 0000000000000..0fca611b2f6e9 --- /dev/null +++ b/scripts/west_commands/runners/blflash.py @@ -0,0 +1,59 @@ +# Copyright (c) 2021 Gerson Fernando Budke +# +# SPDX-License-Identifier: Apache-2.0 + +'''Bouffalo Lab flash tool (blflash) runner for serial boot ROM''' + +from runners.core import ZephyrBinaryRunner, RunnerCaps + +DEFAULT_BLFLASH_PORT = '/dev/ttyUSB0' +DEFAULT_BLFLASH_SPEED = '2000000' + +class BlFlashBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for blflash.''' + + def __init__(self, cfg, blflash='blflash', + port=DEFAULT_BLFLASH_PORT, + speed=DEFAULT_BLFLASH_SPEED): + super().__init__(cfg) + self.blflash = blflash + self.port = port + self.speed = speed + + @classmethod + def name(cls): + return 'blflash' + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={'flash'}) + + @classmethod + def do_add_parser(cls, parser): + parser.add_argument('--blflash', default='blflash', + help='path to blflash, default is blflash') + parser.add_argument('--port', default=DEFAULT_BLFLASH_PORT, + help='serial port to use, default is ' + + str(DEFAULT_BLFLASH_PORT)) + parser.add_argument('--speed', default=DEFAULT_BLFLASH_SPEED, + help='serial port speed to use, default is ' + + DEFAULT_BLFLASH_SPEED) + + @classmethod + def do_create(cls, cfg, args): + return BlFlashBinaryRunner(cfg, + blflash=args.blflash, + port=args.port, + speed=args.speed) + + def do_run(self, command, **kwargs): + self.require(self.blflash) + self.ensure_output('bin') + + cmd_flash = [self.blflash, + 'flash', + self.cfg.bin_file, + '-p', self.port, + '-b', self.speed] + + self.check_call(cmd_flash) diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 3fb08b68a9e1f..66874b18902c1 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -18,6 +18,7 @@ def test_runner_imports(): # zephyr-keep-sorted-start 'arc-nsim', 'blackmagicprobe', + 'blflash', 'bossac', 'canopen', 'dediprog', From 27571961ebb008829fbe6a818fd9eabced1b02ea Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sat, 2 Apr 2022 12:09:04 -0300 Subject: [PATCH 11/21] boards: riscv: Introduce bl604e_iot_dvk Add initial version. Signed-off-by: Gerson Fernando Budke --- .../bl6/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk | 6 + .../bl604e_iot_dvk-pinctrl.dtsi | 26 +++ .../bl6/bl604e_iot_dvk/bl604e_iot_dvk.dts | 51 +++++ .../bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml | 19 ++ .../bl604e_iot_dvk/bl604e_iot_dvk_defconfig | 10 + .../bl6/bl604e_iot_dvk/board.cmake | 23 +++ .../bouffalolab/bl6/bl604e_iot_dvk/board.yml | 6 + .../bl6/bl604e_iot_dvk/doc/img/bl_604e.jpg | Bin 0 -> 97803 bytes .../bl6/bl604e_iot_dvk/doc/index.rst | 179 ++++++++++++++++++ .../bl6/bl604e_iot_dvk/support/bl6.cfg | 79 ++++++++ .../bl6/bl604e_iot_dvk/support/openocd.cfg | 19 ++ boards/bouffalolab/index.rst | 10 + dts/riscv/bouffalolab/bl604e.dtsi | 15 ++ 13 files changed, 443 insertions(+) create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.dts create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk_defconfig create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/board.cmake create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/board.yml create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/doc/img/bl_604e.jpg create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/support/bl6.cfg create mode 100644 boards/bouffalolab/bl6/bl604e_iot_dvk/support/openocd.cfg create mode 100644 boards/bouffalolab/index.rst create mode 100644 dts/riscv/bouffalolab/bl604e.dtsi diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk b/boards/bouffalolab/bl6/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk new file mode 100644 index 0000000000000..ae82bd6f2d8c8 --- /dev/null +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk @@ -0,0 +1,6 @@ +# Copyright (c) 2022-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_BL604E_IOT_DVK + select SOC_BL604E20Q2I diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi new file mode 100644 index 0000000000000..f773fcae87bbe --- /dev/null +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&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/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.dts b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.dts new file mode 100644 index 0000000000000..8648c9363a6b8 --- /dev/null +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.dts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "bl604e_iot_dvk-pinctrl.dtsi" + +/ { + model = "BL604E IOT DVK development board"; + compatible = "bflb,bl604"; + + chosen { + zephyr,flash = &flash0; + zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; + +&cpu0 { + clock-frequency = <192000000>; +}; + +&spi1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4000b000 0x1000 0x23000000 0xc00000>; + flash0: flash@0 { + compatible = "issi,is25lp128", "jedec,spi-nor"; + status = "disabled"; + size = <134217728>; + jedec-id = [96 60 18]; + reg = <0>; + spi-max-frequency = <133000000>; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml new file mode 100644 index 0000000000000..7fad6e6d6118f --- /dev/null +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2022-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +identifier: bl604e_iot_dvk +name: BL604E IOT DVK development board +type: mcu +arch: riscv +ram: 64 +toolchain: + - zephyr +testing: + ignore_tags: + - net + - bluetooth +supported: + - pinctrl + - uart +vendor: bflb diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk_defconfig b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk_defconfig new file mode 100644 index 0000000000000..d736e43f5d50d --- /dev/null +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk_defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2022-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y + +CONFIG_UART_CONSOLE=y +CONFIG_UART_BFLB=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/board.cmake b/boards/bouffalolab/bl6/bl604e_iot_dvk/board.cmake new file mode 100644 index 0000000000000..f9d962c35327c --- /dev/null +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/board.cmake @@ -0,0 +1,23 @@ +# Copyright (c) 2022-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(openocd --cmd-pre-init "source [find bl6.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 0x22008000 0x22014000 rw") +board_runner_args(openocd --gdb-init "mem 0x42008000 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(blflash --port /dev/ttyACM0) +include(${ZEPHYR_BASE}/boards/common/blflash.board.cmake) diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/board.yml b/boards/bouffalolab/bl6/bl604e_iot_dvk/board.yml new file mode 100644 index 0000000000000..843d38b0e8a2f --- /dev/null +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/board.yml @@ -0,0 +1,6 @@ +board: + name: bl604e_iot_dvk + full_name: BL604E IOT DVK development board + vendor: bflb + socs: + - name: bl604e20q2i diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/img/bl_604e.jpg b/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/img/bl_604e.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05700b35504efd37e8f57e83ba664387e070f73d GIT binary patch literal 97803 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�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 + +/ { + soc { + sram0: memory@42020000 { + reg = <0x42020000 DT_SIZE_K(64)>; + }; + }; +}; From 01828dead0b008ffeacadcc6b49deb177ab69ac0 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 31 Aug 2024 11:23:37 +0200 Subject: [PATCH 12/21] west.yml: Drop bouffalolab SDK dependency This replace the SDK 1.4.2 by a direct register access aproach. This means that future operations on hal_bouffalolab do not require any dependency of a SDK from Bouffalo Lab anymore. The code was inspired by the newer SDK 2.0. Signed-off-by: Camille BAUD Signed-off-by: Gerson Fernando Budke --- west.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/west.yml b/west.yml index 7d542993c55bb..9285c4c544f61 100644 --- a/west.yml +++ b/west.yml @@ -164,9 +164,9 @@ manifest: groups: - hal - name: hal_bouffalolab - remote: nandojve + revision: main path: modules/hal/bouffalolab - revision: sdk-v1.4.5 + remote: nandojve groups: - hal - name: hal_espressif From b45434db72063385a257e6418969dbb11f151f24 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 31 Aug 2024 12:58:21 +0200 Subject: [PATCH 13/21] soc: riscv: Rework bl60x to be SDK independent Make all changes on the SoC to remove SDK dependency. Signed-off-by: Camille BAUD Signed-off-by: Gerson Fernando Budke --- modules/Kconfig | 1 + modules/Kconfig.bouffalolab | 6 + modules/hal_bouffalolab/CMakeLists.txt | 58 +- modules/hal_bouffalolab/Kconfig | 54 +- modules/hal_bouffalolab/include/bflb_glb.h | 14 - modules/hal_bouffalolab/include/bflb_gpio.h | 14 - modules/hal_bouffalolab/include/bflb_hbn.h | 14 - .../hal_bouffalolab/include/bflb_pinctrl.h | 15 - modules/hal_bouffalolab/include/bflb_uart.h | 14 - .../hal_bouffalolab/include/bl_ld_sections.h | 25 - soc/bouffalolab/Kconfig | 3 - soc/bouffalolab/bl6/Kconfig.defconfig | 19 - soc/bouffalolab/bl6/rodata.ld | 17 - soc/bouffalolab/bl6/soc.c | 126 --- soc/bouffalolab/{bl6 => bl60x}/CMakeLists.txt | 5 +- soc/bouffalolab/{bl6 => bl60x}/Kconfig | 10 +- soc/bouffalolab/bl60x/Kconfig.defconfig | 25 + soc/bouffalolab/{bl6 => bl60x}/Kconfig.soc | 11 +- soc/bouffalolab/bl60x/soc.c | 874 ++++++++++++++++++ soc/bouffalolab/{bl6 => bl60x}/soc.h | 15 +- soc/bouffalolab/common/CMakeLists.txt | 6 - soc/bouffalolab/common/soc_common.h | 82 -- soc/bouffalolab/common/soc_common_irq.c | 100 -- soc/bouffalolab/common/soc_irq.S | 58 -- soc/bouffalolab/common/vector.S | 39 - soc/bouffalolab/soc.yml | 2 +- 26 files changed, 938 insertions(+), 669 deletions(-) create mode 100644 modules/Kconfig.bouffalolab delete mode 100644 modules/hal_bouffalolab/include/bflb_glb.h delete mode 100644 modules/hal_bouffalolab/include/bflb_gpio.h delete mode 100644 modules/hal_bouffalolab/include/bflb_hbn.h delete mode 100644 modules/hal_bouffalolab/include/bflb_pinctrl.h delete mode 100644 modules/hal_bouffalolab/include/bflb_uart.h delete mode 100644 modules/hal_bouffalolab/include/bl_ld_sections.h delete mode 100644 soc/bouffalolab/bl6/Kconfig.defconfig delete mode 100644 soc/bouffalolab/bl6/rodata.ld delete mode 100644 soc/bouffalolab/bl6/soc.c rename soc/bouffalolab/{bl6 => bl60x}/CMakeLists.txt (61%) rename soc/bouffalolab/{bl6 => bl60x}/Kconfig (66%) create mode 100644 soc/bouffalolab/bl60x/Kconfig.defconfig rename soc/bouffalolab/{bl6 => bl60x}/Kconfig.soc (81%) create mode 100644 soc/bouffalolab/bl60x/soc.c rename soc/bouffalolab/{bl6 => bl60x}/soc.h (82%) delete mode 100644 soc/bouffalolab/common/soc_common.h delete mode 100644 soc/bouffalolab/common/soc_common_irq.c delete mode 100644 soc/bouffalolab/common/soc_irq.S delete mode 100644 soc/bouffalolab/common/vector.S diff --git a/modules/Kconfig b/modules/Kconfig index 491e20baf1c74..5fc054efdb893 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -22,6 +22,7 @@ osource "$(KCONFIG_BINARY_DIR)/Kconfig.modules" source "modules/Kconfig.altera" source "modules/Kconfig.atmel" +source "modules/Kconfig.bouffalolab" source "modules/Kconfig.chre" source "modules/Kconfig.cypress" source "modules/Kconfig.eos_s3" diff --git a/modules/Kconfig.bouffalolab b/modules/Kconfig.bouffalolab new file mode 100644 index 0000000000000..a6870be41085a --- /dev/null +++ b/modules/Kconfig.bouffalolab @@ -0,0 +1,6 @@ +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +config HAS_BOUFFALOLAB_HAL + bool + depends on SOC_FAMILY_BFLB diff --git a/modules/hal_bouffalolab/CMakeLists.txt b/modules/hal_bouffalolab/CMakeLists.txt index 60649b8a7a298..4661a292f4bfe 100644 --- a/modules/hal_bouffalolab/CMakeLists.txt +++ b/modules/hal_bouffalolab/CMakeLists.txt @@ -1,61 +1,15 @@ # Copyright (c) 2021-2024 Gerson Fernando Budke +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) # # SPDX-License-Identifier: Apache-2.0 if(CONFIG_SOC_FAMILY_BFLB) -zephyr_library_named(hal_bouffalolab) - -zephyr_compile_definitions( - ARCH_RISCV -) - -zephyr_library_compile_definitions( - BFLB_USE_HAL_DRIVER - BFLB_USE_CUSTOM_LD_SECTIONS -) - -set(bflb_soc ${CONFIG_SOC_SERIES}02) -set(bflb_drv_dir ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/drivers/${bflb_soc}_driver) -set(bflb_common_dir ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/common) -set(bflb_drv_src_dir ${bflb_drv_dir}/std_drv/src) - -# Global includes to be used outside hal_gigadevice -zephyr_include_directories( - include - ${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/include - - ${bflb_drv_dir}/regs - ${bflb_drv_dir}/startup - ${bflb_drv_dir}/std_drv/inc - - ${bflb_common_dir}/misc -) - -zephyr_library_include_directories( - ${bflb_common_dir}/soft_crc -) - -zephyr_library_sources( - ${bflb_drv_src_dir}/${bflb_soc}_aon.c - ${bflb_drv_src_dir}/${bflb_soc}_ef_ctrl.c - ${bflb_drv_src_dir}/${bflb_soc}_glb.c - ${bflb_drv_src_dir}/${bflb_soc}_hbn.c - ${bflb_drv_src_dir}/${bflb_soc}_l1c.c - ${bflb_drv_src_dir}/${bflb_soc}_pds.c - ${bflb_drv_src_dir}/${bflb_soc}_romapi.c - - ${bflb_common_dir}/soft_crc/softcrc.c -) +if (CONFIG_SOC_SERIES_BL60X) + zephyr_compile_definitions(BL602) +endif() -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_ACOMP ${bflb_drv_src_dir}/${bflb_soc}_acomp.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_ADC ${bflb_drv_src_dir}/${bflb_soc}_adc.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_DAC ${bflb_drv_src_dir}/${bflb_soc}_dac.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_DMA ${bflb_drv_src_dir}/${bflb_soc}_dma.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_I2C ${bflb_drv_src_dir}/${bflb_soc}_i2c.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_IR ${bflb_drv_src_dir}/${bflb_soc}_ir.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_PWM ${bflb_drv_src_dir}/${bflb_soc}_pwm.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_SPI ${bflb_drv_src_dir}/${bflb_soc}_spi.c) -zephyr_library_sources_ifdef(CONFIG_USE_BFLB_UART ${bflb_drv_src_dir}/${bflb_soc}_uart.c) +zephyr_include_directories(${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/include/bouffalolab/${SOC_SERIES}) +zephyr_include_directories(${ZEPHYR_HAL_BOUFFALOLAB_MODULE_DIR}/include) endif() diff --git a/modules/hal_bouffalolab/Kconfig b/modules/hal_bouffalolab/Kconfig index 2e753a1da5341..fee984ac1588f 100644 --- a/modules/hal_bouffalolab/Kconfig +++ b/modules/hal_bouffalolab/Kconfig @@ -1,59 +1,7 @@ # Copyright (c) 2021-2024 Gerson Fernando Budke +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) # # SPDX-License-Identifier: Apache-2.0 config ZEPHYR_HAL_BOUFFALOLAB_MODULE bool - -config HAS_BFLB_HAL - bool - -if HAS_BFLB_HAL - -config USE_BFLB_ACOMP - bool - help - Enable BFLB Analog Comparator (ACOMP) HAL module driver - -config USE_BFLB_ADC - bool - help - Enable BFLB Analog-to-Digital Converter (ADC) HAL module driver - -config USE_BFLB_DAC - bool - help - Enable BFLB Digital-to-Analog Converter (DAC) HAL module driver - -config USE_BFLB_DMA - bool - help - Enable BFLB Direct Memory Access controller (DMA) HAL module driver - -config USE_BFLB_I2C - bool - help - Enable BFLB Inter-Integrated Circuit Interface (I2C) HAL module driver - -config USE_BFLB_IR - bool - help - Enable BFLB Infrared Remote controller (IR) HAL module driver - -config USE_BFLB_PWM - bool - help - Enable BFLB Pulse Width Modulation (PMU) HAL module driver - -config USE_BFLB_SPI - bool - help - Enable BFLB Serial Peripheral Interface(SPI) HAL module driver - -config USE_BFLB_UART - bool - help - Enable BFLB Universal Asynchronous Receiver/Transmitter (UART) - HAL module driver - -endif # HAS_BFLB_HAL diff --git a/modules/hal_bouffalolab/include/bflb_glb.h b/modules/hal_bouffalolab/include/bflb_glb.h deleted file mode 100644 index 03002d8eda59c..0000000000000 --- a/modules/hal_bouffalolab/include/bflb_glb.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_HAL_BFLB_GLB_H_ -#define ZEPHYR_HAL_BFLB_GLB_H_ - -#ifdef CONFIG_SOC_SERIES_BL6 - #include -#endif - -#endif /* ZEPHYR_HAL_BFLB_GLB_H_ */ diff --git a/modules/hal_bouffalolab/include/bflb_gpio.h b/modules/hal_bouffalolab/include/bflb_gpio.h deleted file mode 100644 index ed89a4532abbc..0000000000000 --- a/modules/hal_bouffalolab/include/bflb_gpio.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_HAL_BFLB_GPIO_H_ -#define ZEPHYR_HAL_BFLB_GPIO_H_ - -#ifdef CONFIG_SOC_SERIES_BL6 - #include -#endif - -#endif /* ZEPHYR_HAL_BFLB_GPIO_H_ */ diff --git a/modules/hal_bouffalolab/include/bflb_hbn.h b/modules/hal_bouffalolab/include/bflb_hbn.h deleted file mode 100644 index 2146f89cf5b67..0000000000000 --- a/modules/hal_bouffalolab/include/bflb_hbn.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_HAL_BFLB_HBN_H_ -#define ZEPHYR_HAL_BFLB_HBN_H_ - -#ifdef CONFIG_SOC_SERIES_BL6 - #include -#endif - -#endif /* ZEPHYR_HAL_BFLB_HBN_H_ */ diff --git a/modules/hal_bouffalolab/include/bflb_pinctrl.h b/modules/hal_bouffalolab/include/bflb_pinctrl.h deleted file mode 100644 index 848c2862f70e4..0000000000000 --- a/modules/hal_bouffalolab/include/bflb_pinctrl.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_HAL_BFLB_PINCTRL_H_ -#define ZEPHYR_HAL_BFLB_PINCTRL_H_ - -#ifdef CONFIG_SOC_SERIES_BL6 -# include -#endif -#include - -#endif /* ZEPHYR_HAL_BFLB_PINCTRL_H_ */ diff --git a/modules/hal_bouffalolab/include/bflb_uart.h b/modules/hal_bouffalolab/include/bflb_uart.h deleted file mode 100644 index 903f11c9c4f74..0000000000000 --- a/modules/hal_bouffalolab/include/bflb_uart.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_HAL_BFLB_UART_H_ -#define ZEPHYR_HAL_BFLB_UART_H_ - -#ifdef CONFIG_SOC_SERIES_BL6 - #include -#endif - -#endif /* ZEPHYR_HAL_BFLB_UART_H_ */ diff --git a/modules/hal_bouffalolab/include/bl_ld_sections.h b/modules/hal_bouffalolab/include/bl_ld_sections.h deleted file mode 100644 index c06ae56e65f84..0000000000000 --- a/modules/hal_bouffalolab/include/bl_ld_sections.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __BL_LD_SECTIONS_H -#define __BL_LD_SECTIONS_H - -#define ATTR_STRINGIFY(x) #x -#define ATTR_TOSTRING(x) ATTR_STRINGIFY(x) -#define ATTR_UNI_SYMBOL __FILE__ ATTR_TOSTRING(__LINE__) -#define ATTR_CLOCK_SECTION __attribute__((section(".itcm.sclock_rlt_code." ATTR_UNI_SYMBOL))) -#define ATTR_CLOCK_CONST_SECTION __attribute__((section(".itcm.sclock_rlt_const." ATTR_UNI_SYMBOL))) -#define ATTR_TCM_SECTION __attribute__((section(".itcm.code." ATTR_UNI_SYMBOL))) -#define ATTR_TCM_CONST_SECTION __attribute__((section(".itcm.const." ATTR_UNI_SYMBOL))) -#define ATTR_DTCM_SECTION __attribute__((section(".dtcm.data"))) -#define ATTR_HSRAM_SECTION __attribute__((section(".hsram_code"))) -#define ATTR_DMA_RAM_SECTION __attribute__((section(".system_ram"))) -#define ATTR_HBN_RAM_SECTION __attribute__((section(".hbn_ram_code"))) -#define ATTR_HBN_RAM_CONST_SECTION __attribute__((section(".hbn_ram_data"))) -#define ATTR_FALLTHROUGH() __attribute__((fallthrough)) -#define ATTR_USED __attribute__((__used__)) -#define ATTR_EALIGN(x) __aligned(size) - -#endif /* __BL_LD_SECTIONS_H */ diff --git a/soc/bouffalolab/Kconfig b/soc/bouffalolab/Kconfig index 41120b85d81c7..0420e03a79ac5 100644 --- a/soc/bouffalolab/Kconfig +++ b/soc/bouffalolab/Kconfig @@ -2,9 +2,6 @@ # # SPDX-License-Identifier: Apache-2.0 -config SOC_FAMILY_BFLB - select HAS_BFLB_HAL - if SOC_FAMILY_BFLB rsource "*/Kconfig" diff --git a/soc/bouffalolab/bl6/Kconfig.defconfig b/soc/bouffalolab/bl6/Kconfig.defconfig deleted file mode 100644 index a9c2a820aa3a0..0000000000000 --- a/soc/bouffalolab/bl6/Kconfig.defconfig +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2021-2024 ATL Electronics -# -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_BL6 - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 192000000 - -config NUM_IRQS - default 80 - -config RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET - default 0 - -config RISCV_TRAP_HANDLER_ALIGNMENT - default 8 - -endif # SOC_SERIES_BL6 diff --git a/soc/bouffalolab/bl6/rodata.ld b/soc/bouffalolab/bl6/rodata.ld deleted file mode 100644 index fa5b54db07afe..0000000000000 --- a/soc/bouffalolab/bl6/rodata.ld +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2021-2024 ATL Electronics - * - * SPDX-License-Identifier: Apache-2.0 - */ - -KEEP(*(SORT_NONE( EXCLUDE_FILE( *bl602_glb.o \ - *bl602_pds.o \ - *bl602_common.o \ - *bl602_sf_cfg.o \ - *bl602_sf_cfg_ext*.o* \ - *bl602_sf_ctrl.o \ - *bl602_sflash.o \ - *bl602_sflash_ext*.o* \ - *bl602_xip_sflash.o \ - *bl602_xip_sflash_ext*.o* \ - *bl602_ef_ctrl.o) .rodata*))) diff --git a/soc/bouffalolab/bl6/soc.c b/soc/bouffalolab/bl6/soc.c deleted file mode 100644 index 2aadea88167c9..0000000000000 --- a/soc/bouffalolab/bl6/soc.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2021-2024 ATL Electronics - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Bouffalo Lab RISC-V MCU series initialization code - */ - -#include -#include -#include - -#include -#include -#include - -/* clang-format off */ - -#define ROOT_FCLK_DIV (0) -#define ROOT_BCLK_DIV (1) -#define ROOT_UART_CLOCK_DIV (0) - -static void system_bor_init(void) -{ - HBN_BOR_CFG_Type borCfg = { 1 /* pu_bor */, 0 /* irq_bor_en */, - 1 /* bor_vth */, 1 /* bor_sel */ }; - HBN_Set_BOR_Cfg(&borCfg); -} - -static uint32_t mtimer_get_clk_src_div(void) -{ - return ((SystemCoreClockGet() / (GLB_Get_BCLK_Div() + 1)) - / 1000 / 1000 - 1); -} - -static void system_clock_init(void) -{ - GLB_Set_System_CLK(GLB_PLL_XTAL_40M, GLB_SYS_CLK_PLL160M); - GLB_Set_System_CLK_Div(ROOT_FCLK_DIV, ROOT_BCLK_DIV); - GLB_Set_MTimer_CLK(1, GLB_MTIMER_CLK_BCLK, mtimer_get_clk_src_div()); -} - -static void peripheral_clock_init(void) -{ - GLB_Set_UART_CLK(1, HBN_UART_CLK_160M, ROOT_UART_CLOCK_DIV); -} - -void soc_early_init_hook(void) -{ - uint32_t key; - uint32_t *p; - uint32_t i = 0; - uint32_t tmp = 0; - - key = irq_lock(); - - __disable_irq(); - - /* disable hardware_pullup_pull_down (reg_en_hw_pu_pd = 0) */ - tmp = BL_RD_REG(HBN_BASE, HBN_IRQ_MODE); - tmp = BL_CLR_REG_BIT(tmp, HBN_REG_EN_HW_PU_PD); - BL_WR_REG(HBN_BASE, HBN_IRQ_MODE, tmp); - - /* GLB_Set_EM_Sel(GLB_EM_0KB); */ - tmp = BL_RD_REG(GLB_BASE, GLB_SEAM_MISC); - tmp = BL_SET_REG_BITS_VAL(tmp, GLB_EM_SEL, GLB_EM_0KB); - BL_WR_REG(GLB_BASE, GLB_SEAM_MISC, tmp); - - /* Fix 26M xtal clkpll_sdmin */ - tmp = BL_RD_REG(PDS_BASE, PDS_CLKPLL_SDM); - - if (BL_GET_REG_BITS_VAL(tmp, PDS_CLKPLL_SDMIN) == 0x49D39D) { - tmp = BL_SET_REG_BITS_VAL(tmp, PDS_CLKPLL_SDMIN, 0x49D89E); - BL_WR_REG(PDS_BASE, PDS_CLKPLL_SDM, tmp); - } - - /* Restore default setting*/ - - /* GLB_UART_Sig_Swap_Set(UART_SIG_SWAP_NONE); */ - tmp = BL_RD_REG(GLB_BASE, GLB_PARM); - tmp = BL_SET_REG_BITS_VAL(tmp, GLB_UART_SWAP_SET, UART_SIG_SWAP_NONE); - BL_WR_REG(GLB_BASE, GLB_PARM, tmp); - - /* GLB_JTAG_Sig_Swap_Set(JTAG_SIG_SWAP_NONE); */ - tmp = BL_RD_REG(GLB_BASE, GLB_PARM); - tmp = BL_SET_REG_BITS_VAL(tmp, GLB_JTAG_SWAP_SET, JTAG_SIG_SWAP_NONE); - BL_WR_REG(GLB_BASE, GLB_PARM, tmp); - - /* 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(); - /* global IRQ enable */ - __enable_irq(); - - system_clock_init(); - peripheral_clock_init(); - - irq_unlock(key); -} - -/* identify flash config automatically */ -extern BL_Err_Type flash_init(void); - -void System_Post_Init(void) -{ - PDS_Trim_RC32M(); - HBN_Trim_RC32K(); - flash_init(); -} - -/* clang-format on */ diff --git a/soc/bouffalolab/bl6/CMakeLists.txt b/soc/bouffalolab/bl60x/CMakeLists.txt similarity index 61% rename from soc/bouffalolab/bl6/CMakeLists.txt rename to soc/bouffalolab/bl60x/CMakeLists.txt index 6c3022edc1cb8..f21e11056abb2 100644 --- a/soc/bouffalolab/bl6/CMakeLists.txt +++ b/soc/bouffalolab/bl60x/CMakeLists.txt @@ -1,10 +1,11 @@ # Copyright (c) 2021-2024 ATL Electronics +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) # # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(.) zephyr_sources(soc.c) -zephyr_linker_sources_ifdef(CONFIG_SOC_SERIES_BL6 RODATA rodata.ld) - set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") + +zephyr_code_relocate_ifdef(CONFIG_RISCV_MACHINE_TIMER LIBRARY drivers__timer LOCATION ITCM) diff --git a/soc/bouffalolab/bl6/Kconfig b/soc/bouffalolab/bl60x/Kconfig similarity index 66% rename from soc/bouffalolab/bl6/Kconfig rename to soc/bouffalolab/bl60x/Kconfig index 1a052905eb080..591800a095d5b 100644 --- a/soc/bouffalolab/bl6/Kconfig +++ b/soc/bouffalolab/bl60x/Kconfig @@ -1,15 +1,18 @@ # Copyright (c) 2021-2024 ATL Electronics +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) # # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_BL6 +config SOC_SERIES_BL60X select RISCV - select RISCV_HAS_CPU_IDLE select RISCV_MACHINE_TIMER select RISCV_PRIVILEGED + select RISCV_HAS_CLIC + select RISCV_VECTORED_MODE select ATOMIC_OPERATIONS_C - select COMPRESSED_ISA + select CODE_DATA_RELOCATION select CPU_HAS_FPU + select GEN_IRQ_VECTOR_TABLE select INCLUDE_RESET_VECTOR select SOC_EARLY_INIT_HOOK select XIP @@ -17,6 +20,7 @@ config SOC_SERIES_BL6 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 diff --git a/soc/bouffalolab/bl60x/Kconfig.defconfig b/soc/bouffalolab/bl60x/Kconfig.defconfig new file mode 100644 index 0000000000000..db2799d32cc9e --- /dev/null +++ b/soc/bouffalolab/bl60x/Kconfig.defconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2021-2024 ATL Electronics +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_BL60X + +# On SiFive e24, mtime is a fixed 1 000 000 per second rate. +# riscv_machine_timer uses mtime as if it was mcycle and expects +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 + +config SYS_CLOCK_TICKS_PER_SEC + default 1000 + +config NUM_IRQS + default 80 + +config ARCH_SW_ISR_TABLE_ALIGN + default 64 + +config RISCV_MCAUSE_EXCEPTION_MASK + default 0x3FF + +endif # SOC_SERIES_BL60X diff --git a/soc/bouffalolab/bl6/Kconfig.soc b/soc/bouffalolab/bl60x/Kconfig.soc similarity index 81% rename from soc/bouffalolab/bl6/Kconfig.soc rename to soc/bouffalolab/bl60x/Kconfig.soc index 40c390a672bd7..c8839e612e046 100644 --- a/soc/bouffalolab/bl6/Kconfig.soc +++ b/soc/bouffalolab/bl60x/Kconfig.soc @@ -1,23 +1,24 @@ # Copyright (c) 2021-2024 ATL Electronics +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) # # SPDX-License-Identifier: Apache-2.0 -config SOC_SERIES_BL6 +config SOC_SERIES_BL60X bool select SOC_FAMILY_BFLB help Enable support for BouffaloLab BL6xx MCU series config SOC_SERIES - default "bl6" if SOC_SERIES_BL6 + default "bl60x" if SOC_SERIES_BL60X config SOC_BL602C00Q2I bool - select SOC_SERIES_BL6 + select SOC_SERIES_BL60X config SOC_BL602C20Q2I bool - select SOC_SERIES_BL6 + select SOC_SERIES_BL60X config SOC_BL602C20Q2IS bool @@ -37,7 +38,7 @@ config SOC_BL602l20Q2H config SOC_BL604E20Q2I bool - select SOC_SERIES_BL6 + select SOC_SERIES_BL60X config SOC default "bl602c00q2i" if SOC_BL602C00Q2I diff --git a/soc/bouffalolab/bl60x/soc.c b/soc/bouffalolab/bl60x/soc.c new file mode 100644 index 0000000000000..1e3620f3ef5c0 --- /dev/null +++ b/soc/bouffalolab/bl60x/soc.c @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * Copyright (c) 2024 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 +#include +#include +#include +#include +#include +#include +#include + +/* clang-format off */ + +/* Set Embedded Flash Pullup */ +static void system_bor_init(void) +{ + uint32_t tmp = 0; + + tmp = sys_read32(HBN_BASE + HBN_BOR_CFG_OFFSET); + tmp = (tmp & HBN_BOR_VTH_UMSK) /* borThreshold = 1 */ + | (1U << HBN_BOR_VTH_POS); + tmp = (tmp & HBN_BOR_SEL_UMSK) /* enablePorInBor true */ + | (1U << HBN_BOR_SEL_POS); + tmp = (tmp & HBN_PU_BOR_UMSK) /* enableBor true */ + | (1U << HBN_PU_BOR_POS); + sys_write32(tmp, HBN_BASE + HBN_BOR_CFG_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); +} + +static uint32_t mtimer_get_clk_src_div(void) +{ + uint32_t bclk_div = -1; + + bclk_div = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + bclk_div = (bclk_div & GLB_REG_BCLK_DIV_MSK) >> GLB_REG_BCLK_DIV_POS; + + return ((sys_read32(CORECLOCKREGISTER) / (bclk_div + 1)) / 1000 / 1000 - 1); +} + +static void system_clock_settle(void) +{ + __asm__ volatile (".rept 15 ; nop ; .endr"); +} + +static void system_clock_delay_32M_ms(uint32_t ms) +{ + uint32_t count = 0; + + do { + __asm__ volatile (".rept 32 ; nop ; .endr"); + ++count; + } while (count < ms); +} + +static uint32_t is_pds_busy(void) +{ + uint32_t tmp = 0; + + tmp = sys_read32(BFLB_EF_CTRL_BASE + EF_CTRL_EF_IF_CTRL_0_OFFSET); + if (tmp & EF_CTRL_EF_IF_0_BUSY_MSK) { + return 1; + } + return 0; +} + +/* /!\ only use when running on 32Mhz Oscillator Clock + * (system_set_root_clock(0); + * system_set_root_clock_dividers(0, 0); + * sys_write32(MHZ(32), CORECLOCKREGISTER);) + * Only Use with IRQs off + * returns 0 when error + */ +static uint32_t system_efuse_read_32M(void) +{ + uint32_t tmp = 0; + uint32_t tmp2 = 0; + uint32_t *pefuse_start = (uint32_t *)(BFLB_EF_CTRL_BASE); + uint32_t timeout = 0; + + do { + system_clock_delay_32M_ms(1); + timeout++; + } while (timeout < EF_CTRL_DFT_TIMEOUT_VAL && is_pds_busy() > 0); + + /* do a 'ahb clock' setup */ + 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) + | (EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) + | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) + | (0 << EF_CTRL_EF_IF_POR_DIG_POS) + | (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) + | (0 << EF_CTRL_EF_IF_0_RW_POS) + | (0 << EF_CTRL_EF_IF_0_TRIG_POS); + sys_write32(tmp, BFLB_EF_CTRL_BASE + EF_CTRL_EF_IF_CTRL_0_OFFSET); + system_clock_settle(); + + /* clear PDS cache registry */ + for (uint32_t i = 0; i < EF_CTRL_EFUSE_R0_SIZE / 4; ++i) { + pefuse_start[i] = 0; + } + + /* Load efuse region0 */ + /* not ahb clock setup */ + 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) + | (EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) + | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) + | (0 << EF_CTRL_EF_IF_POR_DIG_POS) + | (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) + | (0 << EF_CTRL_EF_IF_0_RW_POS) + | (0 << EF_CTRL_EF_IF_0_TRIG_POS); + sys_write32(tmp, BFLB_EF_CTRL_BASE + EF_CTRL_EF_IF_CTRL_0_OFFSET); + + /* trigger read */ + 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) + | (EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) + | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) + | (0 << EF_CTRL_EF_IF_POR_DIG_POS) + | (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) + | (0 << EF_CTRL_EF_IF_0_RW_POS) + | (1 << EF_CTRL_EF_IF_0_TRIG_POS); + sys_write32(tmp, BFLB_EF_CTRL_BASE + EF_CTRL_EF_IF_CTRL_0_OFFSET); + system_clock_delay_32M_ms(5); + + /* wait for read to complete */ + do { + system_clock_delay_32M_ms(1); + tmp = sys_read32(BFLB_EF_CTRL_BASE + EF_CTRL_EF_IF_CTRL_0_OFFSET); + } while ((tmp & EF_CTRL_EF_IF_0_BUSY_MSK) + || !(tmp && EF_CTRL_EF_IF_0_AUTOLOAD_DONE_MSK)); + + /* do a 'ahb clock' setup */ + 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) + | (EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) + | (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) + | (0 << EF_CTRL_EF_IF_POR_DIG_POS) + | (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) + | (0 << EF_CTRL_EF_IF_0_RW_POS) + | (0 << EF_CTRL_EF_IF_0_TRIG_POS); + sys_write32(tmp, BFLB_EF_CTRL_BASE + EF_CTRL_EF_IF_CTRL_0_OFFSET); + + /* get trim + * .name = "rc32m", + * .en_addr = 0x0C * 8 + 19, + * .parity_addr = 0x0C * 8 + 18, + * .value_addr = 0x0C * 8 + 10, + * .value_len = 8, + */ + tmp2 = 0x0c * 8 + 19; + tmp = sys_read32(BFLB_EF_CTRL_BASE + (tmp2 / 32) * 4); + if (!(tmp & (1 << (tmp2 % 32)))) { + return 0; + } + + tmp2 = 0x0C * 8 + 10; + tmp = sys_read32(BFLB_EF_CTRL_BASE + (tmp2 / 32) * 4); + tmp = tmp >> (tmp2 % 32); + return tmp & ((1 << 8) - 1); + /* TODO: check trim parity */ +} + +/* /!\ only use when running on 32Mhz Oscillator Clock + */ +static void system_clock_trim_32M(void) +{ + uint32_t tmp = 0; + uint32_t trim = 0; + + trim = system_efuse_read_32M(); + 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); + + system_clock_settle(); +} + +/* 32 Mhz Oscillator: 0 + * crystal: 1 + * PLL and 32M: 2 + * PLL and crystal: 3 + */ +static void system_set_root_clock(uint32_t clock) +{ + uint32_t tmp = 0; + + /* invalid value, fallback to internal 32M */ + if (clock < 0 || clock > 3) { + clock = 0; + } + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + tmp = (tmp & HBN_ROOT_CLK_SEL_UMSK) + | (clock << HBN_ROOT_CLK_SEL_POS); + sys_write32(tmp, HBN_BASE + HBN_GLB_OFFSET); + + system_clock_settle(); +} + +static void system_set_root_clock_dividers(uint32_t hclk_div, uint32_t bclk_div) +{ + uint32_t tmp = 0; + + /* 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); + + /* set core clock ? */ + sys_write32(sys_read32(CORECLOCKREGISTER) / (hclk_div + 1), + CORECLOCKREGISTER); + + system_clock_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); + + system_clock_settle(); +} + +/* HCLK: 0 + * PLL120M: 1 + */ +static void system_set_PKA_clock(uint32_t pka_clock) +{ + uint32_t tmp = 0; + + tmp = sys_read32(GLB_BASE + GLB_SWRST_CFG2_OFFSET); + tmp = (tmp & GLB_PKA_CLK_SEL_UMSK) + | (pka_clock << GLB_PKA_CLK_SEL_POS); + sys_write32(tmp, GLB_BASE + GLB_SWRST_CFG2_OFFSET); +} + +static void system_set_machine_timer_clock_enable(uint32_t enable) +{ + uint32_t tmp = 0; + + if (enable) { + enable = 1; + } + + tmp = sys_read32(GLB_BASE + GLB_CPU_CLK_CFG_OFFSET); + tmp = (tmp & GLB_CPU_RTC_EN_UMSK) + | (enable << 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 system_set_machine_timer_clock(uint32_t enable, uint32_t clock, + uint32_t divider) +{ + uint32_t tmp = 0; + + if (divider > 0x1FFFF) { + divider = 0x1FFFF; + } + + if (clock) { + clock = 1; + } + + /* disable mtime clock */ + system_set_machine_timer_clock_enable(0); + + 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); + + system_set_machine_timer_clock_enable(enable); +} + +/* 0: RC32M + * 1: Crystal + */ +static void system_setup_PLL_set_reference(uint32_t ref) +{ + uint32_t tmp = 0; + + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); + if (ref > 0) { + tmp = (tmp & PDS_CLKPLL_REFCLK_SEL_UMSK) + | (1U << PDS_CLKPLL_REFCLK_SEL_POS); + tmp = (tmp & PDS_CLKPLL_XTAL_RC32M_SEL_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_XTAL_RC32M_SEL_POS); + } else { + tmp = (tmp & PDS_CLKPLL_REFCLK_SEL_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_REFCLK_SEL_POS); + tmp = (tmp & PDS_CLKPLL_XTAL_RC32M_SEL_UMSK) + | (1U << PDS_CLKPLL_XTAL_RC32M_SEL_POS); + } + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); +} + +/* No Crystal: 0 + * 24M: 1 + * 26M: 2 + * 32M: 3 + * 38P4M: 4 + * 40M: 5 + * 32MHz Oscillator : 32 + */ +static void system_setup_PLL(uint32_t crystal) +{ + uint32_t tmp = 0; + + /* TODO: if RC32M, use RC32M as PLL source */ + if (crystal == 32) { + /* make sure we are on RC32M before trim */ + system_set_root_clock(0); + system_set_root_clock_dividers(0, 0); + sys_write32(MHZ(32), CORECLOCKREGISTER); + + /* Trim RC32M */ + system_clock_trim_32M(); + + /* set PLL ref as RC32M */ + system_setup_PLL_set_reference(0); + + } else { + /* PLL ref is crystal */ + system_setup_PLL_set_reference(1); + } + + /* PLL Off */ + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_PU_CLKPLL_SFREG_UMSK) + | ((uint32_t)(0) << PDS_PU_CLKPLL_SFREG_POS); + tmp = (tmp & PDS_PU_CLKPLL_UMSK) + | ((uint32_t)(0) << PDS_PU_CLKPLL_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + /* needs 2 steps ? */ + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_CLKPLL_PU_CP_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_PU_CP_POS); + tmp = (tmp & PDS_CLKPLL_PU_PFD_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_PU_PFD_POS); + tmp = (tmp & PDS_CLKPLL_PU_FBDV_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_PU_FBDV_POS); + tmp = (tmp & PDS_CLKPLL_PU_POSTDIV_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_PU_POSTDIV_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + /* set PLL Parameters */ + /* 26M special treatment */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_CP_OFFSET); + if (crystal == 2) { + tmp = (tmp & PDS_CLKPLL_ICP_1U_UMSK) + | (1U << PDS_CLKPLL_ICP_1U_POS); + tmp = (tmp & PDS_CLKPLL_ICP_5U_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_ICP_5U_POS); + tmp = (tmp & PDS_CLKPLL_INT_FRAC_SW_UMSK) + | (1U << PDS_CLKPLL_INT_FRAC_SW_POS); + } else { + tmp = (tmp & PDS_CLKPLL_ICP_1U_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_ICP_1U_POS); + tmp = (tmp & PDS_CLKPLL_ICP_5U_UMSK) + | ((uint32_t)(2) << PDS_CLKPLL_ICP_5U_POS); + tmp = (tmp & PDS_CLKPLL_INT_FRAC_SW_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_INT_FRAC_SW_POS); + } + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_CP_OFFSET); + + /* More 26M special treatment */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_RZ_OFFSET); + if (crystal == 2) { + tmp = (tmp & PDS_CLKPLL_C3_UMSK) + | ((uint32_t)(2) << PDS_CLKPLL_C3_POS); + tmp = (tmp & PDS_CLKPLL_CZ_UMSK) + | ((uint32_t)(2) << PDS_CLKPLL_CZ_POS); + tmp = (tmp & PDS_CLKPLL_RZ_UMSK) + | ((uint32_t)(5) << PDS_CLKPLL_RZ_POS); + tmp = (tmp & PDS_CLKPLL_R4_SHORT_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_R4_SHORT_POS); + } else { + tmp = (tmp & PDS_CLKPLL_C3_UMSK) + | ((uint32_t)(3) << PDS_CLKPLL_C3_POS); + tmp = (tmp & PDS_CLKPLL_CZ_UMSK) + | (1U << PDS_CLKPLL_CZ_POS); + tmp = (tmp & PDS_CLKPLL_RZ_UMSK) + | (1U << PDS_CLKPLL_RZ_POS); + tmp = (tmp & PDS_CLKPLL_R4_SHORT_UMSK) + | (1U << PDS_CLKPLL_R4_SHORT_POS); + } + tmp = (tmp & PDS_CLKPLL_R4_UMSK) + | ((uint32_t)(2) << PDS_CLKPLL_R4_POS); + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_RZ_OFFSET); + + /* set pll dividers */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); + tmp = (tmp & PDS_CLKPLL_POSTDIV_UMSK) + | ((uint32_t)(0x14) << PDS_CLKPLL_POSTDIV_POS); + tmp = (tmp & PDS_CLKPLL_REFDIV_RATIO_UMSK) + | ((uint32_t)(2) << PDS_CLKPLL_REFDIV_RATIO_POS); + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_TOP_CTRL_OFFSET); + + /* set PLL SDMIN */ + /* Isn't this already set at boot by the rom settings + * and we can query the value? + */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_SDM_OFFSET); + switch (crystal) { + case 0: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x3C0000) << PDS_CLKPLL_SDMIN_POS); + break; + case 1: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x500000) << PDS_CLKPLL_SDMIN_POS); + break; + case 3: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x3C0000) << PDS_CLKPLL_SDMIN_POS); + break; + case 4: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x320000) << PDS_CLKPLL_SDMIN_POS); + break; + case 5: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x300000) << PDS_CLKPLL_SDMIN_POS); + break; + case 2: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x49D39D) << PDS_CLKPLL_SDMIN_POS); + break; + case 32: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x3C0000) << PDS_CLKPLL_SDMIN_POS); + break; + default: + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | ((uint32_t)(0x3C0000) << PDS_CLKPLL_SDMIN_POS); + break; + } + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_SDM_OFFSET); + + /* phase comparator settings? */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_FBDV_OFFSET); + tmp = (tmp & PDS_CLKPLL_SEL_FB_CLK_UMSK) + | (1U << PDS_CLKPLL_SEL_FB_CLK_POS); + tmp = (tmp & PDS_CLKPLL_SEL_SAMPLE_CLK_UMSK) + | (1U << PDS_CLKPLL_SEL_SAMPLE_CLK_POS); + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_FBDV_OFFSET); + + /* Turn PLL back ON */ + /* frequency stabilization ? */ + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_PU_CLKPLL_SFREG_UMSK) + | (1U << PDS_PU_CLKPLL_SFREG_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + /* let settle for a while (5 us in SDK), we may not be + * running at 32Mhz right now + */ + system_clock_delay_32M_ms(2); + + /* enable PPL clock actual? */ + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_PU_CLKPLL_UMSK) + | (1U << PDS_PU_CLKPLL_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + /* More power up sequencing*/ + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_CLKPLL_PU_CP_UMSK) + | (1U << PDS_CLKPLL_PU_CP_POS); + tmp = (tmp & PDS_CLKPLL_PU_PFD_UMSK) + | (1U << PDS_CLKPLL_PU_PFD_POS); + tmp = (tmp & PDS_CLKPLL_PU_FBDV_UMSK) + | (1U << PDS_CLKPLL_PU_FBDV_POS); + tmp = (tmp & PDS_CLKPLL_PU_POSTDIV_UMSK) + | (1U << PDS_CLKPLL_PU_POSTDIV_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + system_clock_delay_32M_ms(2); + + /* reset couple things one by one? */ + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_CLKPLL_SDM_RESET_UMSK) + | (1U << PDS_CLKPLL_SDM_RESET_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_CLKPLL_RESET_FBDV_UMSK) + | (1U << PDS_CLKPLL_RESET_FBDV_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_CLKPLL_RESET_FBDV_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_RESET_FBDV_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + + tmp = sys_read32(PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); + tmp = (tmp & PDS_CLKPLL_SDM_RESET_UMSK) + | ((uint32_t)(0) << PDS_CLKPLL_SDM_RESET_POS); + sys_write32(tmp, PDS_BASE + PDS_PU_RST_CLKPLL_OFFSET); +} + +/* copied over from driver for convenience */ +static uint32_t system_uart_bflb_get_crystal_frequency(void) +{ + uint32_t tmp; + + /* get clkpll_sdmin */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_SDM_OFFSET); + tmp = (tmp & PDS_CLKPLL_SDMIN_MSK) >> PDS_CLKPLL_SDMIN_POS; + + /* + * The 'Sigma Delta Modulator Input' scales the PLL output relative to the + * input frequency (eg value is x2, output frequency doubles), it's a + * direct indicator of the XCLK (crystal or 32M osc) frequency to go in the + * PLL. + * + * This value can be read from efuse or from the firmware header which will + * be implemented in the future. + */ + switch (tmp) { + case 0x500000: + return MHZ(24); + case 0x3C0000: + return MHZ(32); + case 0x320000: + return MHZ(38.4); + case 0x300000: + return MHZ(40); + case 0x49D39D: + return MHZ(26); + default: + return MHZ(32); + } +} + +/* Frequency Source: + * No Crystal: 0 + * 24M: 1 + * 26M: 2 + * 32M: 3 + * 38P4M: 4 + * 40M: 5 + * 32MHz Oscillator: 32 + * + * /!\ When Frequency Source is 32M, we do not power crystal + * + * Clock Frequency: + * Crystal: 0 + * PLL 48MHz: 1 + * PLL 120Mhz: 2 + * PLL 160Mhz: 3 + * PLL 192Mhz: 4 + * 32MHz Oscillator : 32 + * + * /!\ When Clock Frequency is 32M, we do not power crystal or PLL + */ +static void system_init_root_clock(uint32_t crystal, + uint32_t clock_frequency_source) +{ + uint32_t tmp = 0; + uint32_t xtal_power_timeout = 0; + + + /* 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 clock to internal 32MHz Oscillator as failsafe */ + system_set_root_clock(0); + system_set_root_clock_dividers(0, 0); + sys_write32(MHZ(32), CORECLOCKREGISTER); + + system_set_PKA_clock(0); + + if (clock_frequency_source == 32) { + return; + } + + if (crystal != 32) { + /* 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 */ + /* TODO: figure way to communicate this failed */ + do { + system_clock_delay_32M_ms(1); + tmp = sys_read32(AON_BASE + AON_TSEN_OFFSET); + xtal_power_timeout++; + } while (!(tmp & AON_XTAL_RDY_MSK) && xtal_power_timeout < 120); + } + + /* power PLL + * This code path only when PLL! + */ + system_setup_PLL(crystal); + /* Big settle, 55us in SDK */ + system_clock_delay_32M_ms(10); + + /* enable all 'PDS' clocks */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_OUTPUT_EN_OFFSET); + tmp |= 0x1FF; + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_OUTPUT_EN_OFFSET); + + /* glb enable pll 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); + + /* set PLL to use in GLB*/ + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_PLL_SEL_UMSK) + | ((uint32_t)(clock_frequency_source - 1) << GLB_REG_PLL_SEL_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG0_OFFSET); + + /* set root clock settings */ + switch (clock_frequency_source) { + case 32: + __ASSERT(clock_frequency_source == 32, "not supposed to be here, returned earlier"); + break; + case 0: + system_set_root_clock(1); + sys_write32(system_uart_bflb_get_crystal_frequency(), CORECLOCKREGISTER); + break; + case 1: + system_set_root_clock(crystal == 32 ? 2 : 3); + sys_write32(MHZ(48), CORECLOCKREGISTER); + break; + case 2: + system_set_root_clock_dividers(0, 1); + system_set_root_clock(crystal == 32 ? 2 : 3); + sys_write32(MHZ(120), CORECLOCKREGISTER); + break; + case 3: + /* TODO: enable rom access 2T*/ + system_set_root_clock_dividers(0, 1); + system_set_root_clock(crystal == 32 ? 2 : 3); + sys_write32(MHZ(160), CORECLOCKREGISTER); + break; + case 4: + /* TODO: enable rom access 2T*/ + system_set_root_clock_dividers(0, 1); + system_set_root_clock(crystal == 32 ? 2 : 3); + sys_write32(MHZ(192), CORECLOCKREGISTER); + break; + default: + __ASSERT(false, "Invalid root clock frequency source"); + break; + } + + /* settle */ + system_clock_delay_32M_ms(10); + + /* we have PLL now */ + system_set_PKA_clock(1); +} + +static void uart_set_clock_enable(uint32_t enable) +{ + uint32_t tmp = 0; + + if (enable) { + enable = 1; + } + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG2_OFFSET); + tmp = (tmp & GLB_UART_CLK_EN_UMSK) + | (enable << GLB_UART_CLK_EN_POS); + sys_write32(tmp, GLB_BASE + GLB_CLK_CFG2_OFFSET); +} + +/* Clock: + * FCLK: 0 + * 160 Mhz PLL: 1 + * When using PLL root clock, we can use either setting, when using the 32Mhz + * Oscillator with a uninitialized PLL, only FCLK will be available. + */ +static void uart_set_clock(uint32_t enable, uint32_t clock, uint32_t divider) +{ + uint32_t tmp = 0; + + if (divider > 0x7) { + divider = 0x7; + } + + if (clock) { + clock = 1; + } + /* disable uart clock */ + uart_set_clock_enable(0); + + 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); + + uart_set_clock_enable(enable); +} + + +/* TODO: should take crystal type, defaults to 40Mhz crystal for BL602 as seems + * the most common + */ +#define USE_CRYSTALL_32MHZ 0 +static void system_clock_init(void) +{ +#if USE_CRYSTALL_32MHZ + system_init_root_clock(0, 32); + system_set_root_clock_dividers(0, 0); + system_clock_trim_32M(); +#else + system_init_root_clock(5, 4); + system_set_root_clock_dividers(0, 2); +#endif + system_set_machine_timer_clock(1, 0, mtimer_get_clk_src_div()); +} + +static void peripheral_clock_init(void) +{ + uint32_t regval = sys_read32(GLB_BASE + GLB_CGEN_CFG1_OFFSET); + /* enable UART0 clock routing */ + regval |= (1 << 16); + /* enable I2C0 clock routing */ + regval |= (1 << 19); + sys_write32(regval, GLB_BASE + GLB_CGEN_CFG1_OFFSET); + uart_set_clock(1, 1, 0); +} + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + * So the init priority has to be 0 (zero). + * + * @return 0 + */ +void soc_early_init_hook(void) +{ + uint32_t key; + uint32_t *p; + uint32_t i = 0; + uint32_t tmp = 0; + + 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) + | ((uint32_t)(0) << GLB_EM_SEL_POS); + sys_write32(tmp, GLB_BASE + GLB_SEAM_MISC_OFFSET); + + /* Fix 26M xtal clkpll_sdmin */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_SDM_OFFSET); + + if ((tmp & PDS_CLKPLL_SDMIN_MSK) == 0x49D39D) { + tmp = (tmp & PDS_CLKPLL_SDMIN_UMSK) + | (uint32_t)(0x49D89E); + sys_write32(tmp, PDS_BASE + PDS_CLKPLL_SDM_OFFSET); + } + + tmp = sys_read32(GLB_BASE + GLB_PARM_OFFSET); + /* GLB_UART_Sig_Swap_Set(UART_SIG_SWAP_NONE); + * no swap = 0 + * see bl602_glb.h for other possible values + */ + tmp = (tmp & GLB_UART_SWAP_SET_UMSK) + | ((uint32_t)(0) << GLB_UART_SWAP_SET_POS); + /* GLB_JTAG_Sig_Swap_Set(JTAG_SIG_SWAP_NONE); */ + tmp = (tmp & GLB_JTAG_SWAP_SET_UMSK) + | ((uint32_t)(0) << GLB_JTAG_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(); + + system_clock_init(); + peripheral_clock_init(); + + irq_unlock(key); + + /* wait 10 ms for peripherals to be ready */ + k_timepoint_t end_timeout = sys_timepoint_calc(K_MSEC(10)); + + while (!sys_timepoint_expired(end_timeout)) { + } +} + +/* clang-format on */ diff --git a/soc/bouffalolab/bl6/soc.h b/soc/bouffalolab/bl60x/soc.h similarity index 82% rename from soc/bouffalolab/bl6/soc.h rename to soc/bouffalolab/bl60x/soc.h index a29854af2201b..80ceb550d7f7a 100644 --- a/soc/bouffalolab/bl6/soc.h +++ b/soc/bouffalolab/bl60x/soc.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021-2024 ATL Electronics + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,19 +16,12 @@ #define _SOC__H_ #include -#include <../common/soc_common.h> #ifndef _ASMLANGUAGE /* Add include for DTS generated information */ #include -#if defined(CONFIG_SOC_SERIES_BL6) -#include -#else -#error Library does not support the specified device. -#endif - /* clang-format off */ /* RISC-V Machine Timer configuration */ @@ -39,9 +33,16 @@ #define RISCV_RAM_SIZE KB(DT_SRAM_SIZE) #define SOC_BOUFFALOLAB_BL_PLL160_FREQ_HZ (160000000) +#define SOC_BOUFFALOLAB_BL_PLL96_FREQ_HZ (96000000) #define SOC_BOUFFALOLAB_BL_HCLK_FREQ_HZ \ DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency) +#ifdef CONFIG_CODE_DATA_RELOCATION +#define ITCMF __attribute__((section(".itcm"))) +#else +#define ITCMF +#endif + /* clang-format on */ #endif /* !_ASMLANGUAGE */ diff --git a/soc/bouffalolab/common/CMakeLists.txt b/soc/bouffalolab/common/CMakeLists.txt index a3bc7c9e57125..d7a8e877baaf4 100644 --- a/soc/bouffalolab/common/CMakeLists.txt +++ b/soc/bouffalolab/common/CMakeLists.txt @@ -7,9 +7,3 @@ zephyr_include_directories(.) zephyr_sources_ifdef(CONFIG_RISCV_PRIVILEGED soc_common_irq_privileged.c ) - -zephyr_sources_ifndef(CONFIG_RISCV_PRIVILEGED - soc_irq.S - soc_common_irq.c - vector.S - ) diff --git a/soc/bouffalolab/common/soc_common.h b/soc/bouffalolab/common/soc_common.h deleted file mode 100644 index 532ced1721445..0000000000000 --- a/soc/bouffalolab/common/soc_common.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file interrupt management code for riscv SOCs supporting the SiFive clic - */ - -#ifndef __SOC_COMMON_H_ -#define __SOC_COMMON_H_ - -/* clang-format off */ - -/* IRQ numbers */ -#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ -#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ -#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ - -/* ECALL Exception numbers */ -#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ -#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ - -/* SOC-specific MCAUSE bitfields */ -#ifdef CONFIG_64BIT -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 63) -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFFFFFFFFFF -#else -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 31) -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF -#endif - -/* SOC-Specific EXIT ISR command */ -#define SOC_ERET mret - -/* CLINT Base Address */ - -#define CLIC_TIMER_ENABLE_ADDRESS (0x02800407) - -/* In mstatus register */ - -#define SOC_MIE_MSIE (0x1 << 3) /* Machine Software Interrupt Enable */ - -/* IRQ 0-15 : (exception:interrupt=0) */ - -#define SOC_IRQ_IAMISALIGNED (0) /* Instruction Address Misaligned */ -#define SOC_IRQ_IAFAULT (1) /* Instruction Address Fault */ -#define SOC_IRQ_IINSTRUCTION (2) /* Illegal Instruction */ -#define SOC_IRQ_BPOINT (3) /* Break Point */ -#define SOC_IRQ_LAMISALIGNED (4) /* Load Address Misaligned */ -#define SOC_IRQ_LAFAULT (5) /* Load Access Fault */ -#define SOC_IRQ_SAMISALIGNED (6) /* Store/AMO Address Misaligned */ -#define SOC_IRQ_SAFAULT (7) /* Store/AMO Access Fault */ -#define SOC_IRQ_ECALLU (8) /* Environment Call from U-mode */ - /* 9-10: Reserved */ -#define SOC_IRQ_ECALLM (11) /* Environment Call from M-mode */ - /* 12-15: Reserved */ - /* IRQ 16- : (async event:interrupt=1) */ -#define SOC_IRQ_NUM_BASE (16) -#define SOC_IRQ_ASYNC (16) - -/* Machine Software Int */ -#define SOC_IRQ_MSOFT (SOC_IRQ_ASYNC + RISCV_MACHINE_SOFT_IRQ) -/* Machine Timer Int */ -#define SOC_IRQ_MTIMER (SOC_IRQ_ASYNC + RISCV_MACHINE_TIMER_IRQ) -/* Machine External Int */ -#define SOC_IRQ_MEXT (SOC_IRQ_ASYNC + RISCV_MACHINE_EXT_IRQ) - -/* Machine Global External Interrupt */ -#define SOC_NR_MGEI_IRQS (64) - -/* Total number of IRQs */ -#define SOC_NR_IRQS (SOC_NR_MGEI_IRQS + SOC_IRQ_NUM_BASE) - -/* clang-format on */ - -#endif /* __SOC_COMMON_H_ */ diff --git a/soc/bouffalolab/common/soc_common_irq.c b/soc/bouffalolab/common/soc_common_irq.c deleted file mode 100644 index 38ea2e623d04c..0000000000000 --- a/soc/bouffalolab/common/soc_common_irq.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief interrupt management code for riscv SOCs supporting the SiFive clic - */ -#include -#include -#include - -/* clang-format off */ - -static void clic_irq_enable(unsigned int irq) -{ - *(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIE + irq) = 1; -} - -static void clic_irq_disable(unsigned int irq) -{ - *(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIE + irq) = 0; -} - -void arch_irq_enable(unsigned int irq) -{ - uint32_t mie; - - if (irq == SOC_IRQ_MSOFT) { - - /* Read mstatus & set machine software interrupt enable in mie */ - - __asm__ volatile("csrrs %0, mie, %1" - : "=r"(mie) - : "r"(BIT(RISCV_MACHINE_SOFT_IRQ))); - - } else if (irq == SOC_IRQ_MTIMER) { - *(volatile uint8_t *)CLIC_TIMER_ENABLE_ADDRESS = 1; - - /* Read mstatus & set machine timer interrupt enable in mie */ - __asm__ volatile("csrrs %0, mie, %1" - : "=r"(mie) - : "r"(BIT(RISCV_MACHINE_TIMER_IRQ) - | BIT(RISCV_MACHINE_EXT_IRQ))); - } else { - clic_irq_enable(irq - SOC_IRQ_ASYNC); - } -} - -void arch_irq_disable(unsigned int irq) -{ - uint32_t mie; - - if (irq == SOC_IRQ_MSOFT) { - - /* Read mstatus & set machine software interrupt enable in mie */ - - __asm__ volatile("csrrc %0, mie, %1" - : "=r"(mie) - : "r"(BIT(RISCV_MACHINE_SOFT_IRQ))); - - } else if (irq == SOC_IRQ_MTIMER) { - *(volatile uint8_t *)CLIC_TIMER_ENABLE_ADDRESS = 0; - - /* Read mstatus & set machine timer interrupt enable in mie */ - __asm__ volatile("csrrc %0, mie, %1" - : "=r"(mie) - : "r"(BIT(RISCV_MACHINE_TIMER_IRQ) - | BIT(RISCV_MACHINE_EXT_IRQ))); - } else { - clic_irq_disable(irq - SOC_IRQ_ASYNC); - } -} - -void arch_irq_priority_set(unsigned int irq, unsigned int prio) -{ - ARG_UNUSED(irq); - ARG_UNUSED(prio); -} - -int arch_irq_is_enabled(unsigned int irq) -{ - uint32_t mie; - - /* Enable MEIE (machine external interrupt enable) */ - __asm__ volatile("csrrs %0, mie, %1" - : "=r"(mie) - : "r"(BIT(RISCV_MACHINE_EXT_IRQ))); - - /* Read mstatus & set machine interrupt enable (MIE) in mstatus */ - __asm__ volatile("csrrs %0, mstatus, %1" - : "=r"(mie) - : "r"(MSTATUS_MIE)); - - return !!(mie & SOC_MIE_MSIE); -} - -/* clang-format on */ diff --git a/soc/bouffalolab/common/soc_irq.S b/soc/bouffalolab/common/soc_irq.S deleted file mode 100644 index b2fabf12035c8..0000000000000 --- a/soc/bouffalolab/common/soc_irq.S +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * common interrupt management code for riscv SOCs supporting the riscv - * privileged architecture specification - */ -#include -#include -#include -#include -#include - -/* exports */ -GTEXT(__soc_handle_irq) - -/* - * SOC-specific function to handle pending IRQ number generating the interrupt. - * Exception number is given as parameter via register a0. - */ -SECTION_FUNC(exception.other, __soc_handle_irq) - /* Clear exception number from CSR mip register */ - li t1, 1 - sll t0, t1, a0 - csrrc t1, mip, t0 - - /* Return */ - jalr x0, ra - -/* - * __soc_is_irq is defined as .weak to allow re-implementation by - * SOCs that does not truly follow the riscv privilege specification. - */ -WTEXT(__soc_is_irq) - -/* - * SOC-specific function to determine if the exception is the result of a - * an interrupt or an exception - * return 1 (interrupt) or 0 (exception) - * - */ -SECTION_FUNC(exception.other, __soc_is_irq) - /* Read mcause and check if interrupt bit is set */ - csrr t0, mcause - li t1, SOC_MCAUSE_IRQ_MASK - and t0, t0, t1 - - /* If interrupt bit is not set, return with 0 */ - addi a0, x0, 0 - beqz t0, not_interrupt - addi a0, a0, 1 - -not_interrupt: - /* return */ - jalr x0, ra diff --git a/soc/bouffalolab/common/vector.S b/soc/bouffalolab/common/vector.S deleted file mode 100644 index d23b9dd07c267..0000000000000 --- a/soc/bouffalolab/common/vector.S +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021-2024 Gerson Fernando Budke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/* exports */ -GTEXT(__start) - -/* imports */ -GTEXT(__initialize) -GTEXT(_isr_wrapper) - -SECTION_FUNC(vectors, __start) - .cfi_startproc - - .option norvc - - /* Inform the debugger that there is nowhere to backtrace */ - .cfi_undefined ra - - /* Disable interrupts */ - li t0, MSTATUS_MIE - csrc mstatus, t0 - - /* - * Set mtvec (Machine Trap-Vector Base-Address Register) - * CLINT Direct mode - */ - la t0, _isr_wrapper - csrw mtvec, t0 - - /* Jump to __initialize */ - tail __initialize - - .cfi_endproc diff --git a/soc/bouffalolab/soc.yml b/soc/bouffalolab/soc.yml index 5cedea0bb30f3..8aafe0d436798 100644 --- a/soc/bouffalolab/soc.yml +++ b/soc/bouffalolab/soc.yml @@ -1,7 +1,7 @@ family: - name: bouffalolab_bflb series: - - name: bl6 + - name: bl60x socs: - name: bl602c00q2i - name: bl602c20q2i From d032c7396a32f75115282ad77223c005fa3889c5 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 31 Aug 2024 13:03:31 +0200 Subject: [PATCH 14/21] dts: riscv: bouffalolab: Update bl60x series cpu Update the BL60x cpu devicetree definitions. Signed-off-by: Camille BAUD Signed-off-by: Gerson Fernando Budke --- dts/riscv/bouffalolab/bl602.dtsi | 10 +------- dts/riscv/bouffalolab/bl604e.dtsi | 10 +------- .../bouffalolab/{bl6.dtsi => bl60x.dtsi} | 23 ++++++++----------- 3 files changed, 12 insertions(+), 31 deletions(-) rename dts/riscv/bouffalolab/{bl6.dtsi => bl60x.dtsi} (89%) diff --git a/dts/riscv/bouffalolab/bl602.dtsi b/dts/riscv/bouffalolab/bl602.dtsi index a29c538ca96f7..bb54598cd65a4 100644 --- a/dts/riscv/bouffalolab/bl602.dtsi +++ b/dts/riscv/bouffalolab/bl602.dtsi @@ -4,12 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - -/ { - soc { - sram0: memory@42020000 { - reg = <0x42020000 DT_SIZE_K(64)>; - }; - }; -}; +#include diff --git a/dts/riscv/bouffalolab/bl604e.dtsi b/dts/riscv/bouffalolab/bl604e.dtsi index 187e680d3f156..3958721aa9f1a 100644 --- a/dts/riscv/bouffalolab/bl604e.dtsi +++ b/dts/riscv/bouffalolab/bl604e.dtsi @@ -4,12 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - -/ { - soc { - sram0: memory@42020000 { - reg = <0x42020000 DT_SIZE_K(64)>; - }; - }; -}; +#include diff --git a/dts/riscv/bouffalolab/bl6.dtsi b/dts/riscv/bouffalolab/bl60x.dtsi similarity index 89% rename from dts/riscv/bouffalolab/bl6.dtsi rename to dts/riscv/bouffalolab/bl60x.dtsi index e8ebcce4e455b..8056084b05adb 100644 --- a/dts/riscv/bouffalolab/bl6.dtsi +++ b/dts/riscv/bouffalolab/bl60x.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2021-2024 ATL Electronics + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,6 +54,7 @@ sram0: memory@42020000 { compatible = "mmio-sram"; + reg = <0x42020000 DT_SIZE_K(64)>; }; sram1: memory@42030000 { compatible = "mmio-sram"; @@ -83,11 +85,11 @@ ranges = <0x40000000 0x40000000 0x1000>; status = "okay"; - glb: gpio@40000000 { + gpio: gpio@40000000 { compatible = "bflb,bl-gpio"; reg = <0x40000000 0x1000>; interrupts = <1 0>; - interrupt-parent = <&ictrl>; + interrupt-parent = <&clic>; gpio-controller; #gpio-cells = <2>; #bflb,pin-cells = <2>; @@ -98,20 +100,17 @@ spi0: spi@4000a200 { compatible = "bflb,bl-spi"; reg = <0x4000a200 0x100>; - peripheral-id = <0>; - interrupts = <27 0>; - interrupt-parent = <&ictrl>; + interrupts = <43 0>; + interrupt-parent = <&clic>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; }; - spi1: spi@4000b000 { compatible = "bflb,bl-qspi"; reg = <0x4000b000 0x1000>; - peripheral-id = <0>; - interrupts = <23 0>; - interrupt-parent = <&ictrl>; + interrupts = <39 0>; + interrupt-parent = <&clic>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -120,17 +119,15 @@ uart0: uart@4000a000 { compatible = "bflb,bl-uart"; reg = <0x4000a000 0x100>; - peripheral-id = <0>; interrupts = <29 0>; - interrupt-parent = <&ictrl>; + interrupt-parent = <&clic>; status = "disabled"; }; uart1: uart@4000a100 { compatible = "bflb,bl-uart"; reg = <0x4000a100 0x100>; - peripheral-id = <1>; interrupts = <30 0>; - interrupt-parent = <&ictrl>; + interrupt-parent = <&clic>; status = "disabled"; }; }; From 902bb4e6ab19e1616f75a314056d3d8037aca0a4 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 31 Aug 2024 14:49:25 +0200 Subject: [PATCH 15/21] drivers: pinctrl: bouffalolab: Update pinctrl driver Update pinctrl driver to be SDK independent. Signed-off-by: Camille BAUD Signed-off-by: Gerson Fernando Budke --- drivers/pinctrl/pinctrl_bflb.c | 127 +++++++++++++++--- dts/riscv/bouffalolab/bl602.dtsi | 1 + dts/riscv/bouffalolab/bl604e.dtsi | 1 + .../drivers/pinctrl/pinctrl_soc_bflb_common.h | 1 + soc/bouffalolab/bl60x/CMakeLists.txt | 1 + 5 files changed, 112 insertions(+), 19 deletions(-) diff --git a/drivers/pinctrl/pinctrl_bflb.c b/drivers/pinctrl/pinctrl_bflb.c index 2848e1dd5cc62..d4593289ec115 100644 --- a/drivers/pinctrl/pinctrl_bflb.c +++ b/drivers/pinctrl/pinctrl_bflb.c @@ -1,42 +1,131 @@ /* * Copyright (c) 2021-2024 Gerson Fernando Budke + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) * * SPDX-License-Identifier: Apache-2.0 */ #include #include -#include -#include -#include /* clang-format off */ +#include +#if defined(CONFIG_SOC_SERIES_BL60X) +# include +#else +# error Pinctrl definitions does not exists for this platform. +#endif + +static void pinctrl_blfb_configure_uart(uint8_t pin, uint8_t func) +{ + uint32_t regval; + uint8_t sig; + uint8_t sig_pos; + + regval = sys_read32(GLB_BASE + GLB_UART_SIG_SEL_0_OFFSET); + + sig = pin % 8; + sig_pos = sig << 2; + + regval &= (~(0x0f << sig_pos)); + regval |= (func << sig_pos); + + for (uint8_t i = 0; i < 8; i++) { + /* reset other sigs which are the same with uart_func */ + sig_pos = i << 2; + if (((regval & (0x0f << sig_pos)) == (func << sig_pos)) + && (i != sig) && (func != 0x0f)) { + regval &= (~(0x0f << sig_pos)); + regval |= (0x0f << sig_pos); + } + } + + sys_write32(regval, GLB_BASE + GLB_UART_SIG_SEL_0_OFFSET); +} + +static void pinctrl_bflb_init_pin(pinctrl_soc_pin_t pin) +{ + uint8_t drive; + uint8_t function; + uint16_t mode; + uint32_t regval; + uint8_t real_pin; + uint8_t is_odd = 0; + uint32_t cfg = 0; + uint32_t cfg_address; + + real_pin = BFLB_PINMUX_GET_PIN(pin); + function = BFLB_PINMUX_GET_FUN(pin); + mode = BFLB_PINMUX_GET_MODE(pin); + drive = BFLB_PINMUX_GET_DRIVER_STRENGTH(pin); + + /* Disable output anyway */ + regval = sys_read32(GLB_BASE + GLB_GPIO_CFGCTL34_OFFSET + ((real_pin >> 5) << 2)); + regval &= ~(1 << (pin & 0x1f)); + sys_write32(regval, GLB_BASE + GLB_GPIO_CFGCTL34_OFFSET + ((real_pin >> 5) << 2)); + + is_odd = real_pin & 1; + + cfg_address = GLB_BASE + GLB_GPIO_CFGCTL0_OFFSET + (real_pin / 2 * 4); + cfg = sys_read32(cfg_address); + cfg &= ~(0xffff << (16 * is_odd)); + + regval = sys_read32(GLB_BASE + GLB_GPIO_CFGCTL34_OFFSET + ((real_pin >> 5) << 2)); + + if (mode == BFLB_PINMUX_MODE_analog) { + regval &= ~(1 << (real_pin & 0x1f)); + function = 10; + } else if (mode == BFLB_PINMUX_MODE_periph) { + cfg |= (1 << (is_odd * 16 + 0)); + regval &= ~(1 << (real_pin & 0x1f)); + } else { + function = 11; + + if (mode == BFLB_PINMUX_MODE_input) { + cfg |= (1 << (is_odd * 16 + 0)); + } + + if (mode == BFLB_PINMUX_MODE_output) { + regval |= (1 << (real_pin & 0x1f)); + } + } + + sys_write32(regval, GLB_BASE + GLB_GPIO_CFGCTL34_OFFSET + ((real_pin >> 5) << 2)); + + uint8_t pull_up = BFLB_PINMUX_GET_PULL_UP(pin); + uint8_t pull_down = BFLB_PINMUX_GET_PULL_DOWN(pin); + + if (pull_up) { + cfg |= (1 << (is_odd * 16 + 4)); + } else if (pull_down) { + cfg |= (1 << (is_odd * 16 + 5)); + } + + if (BFLB_PINMUX_GET_SMT(pin)) { + cfg |= (1 << (is_odd * 16 + 1)); + } + + cfg |= (drive << (is_odd * 16 + 2)); + cfg |= (function << (is_odd * 16 + 8)); + sys_write32(cfg, cfg_address); +} + int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { - GLB_GPIO_Cfg_Type pincfg; uint8_t i; ARG_UNUSED(reg); - for (i = 0U; i < pin_cnt; i++) { - pincfg.gpioFun = BFLB_PINMUX_GET_FUN(pins[i]); - pincfg.gpioMode = BFLB_PINMUX_GET_MODE(pins[i]); - pincfg.gpioPin = BFLB_PINMUX_GET_PIN(pins[i]); - pincfg.pullType = BFLB_PINMUX_GET_PULL_MODES(pins[i]); - pincfg.smtCtrl = BFLB_PINMUX_GET_SMT(pins[i]); - pincfg.drive = BFLB_PINMUX_GET_DRIVER_STRENGTH(pins[i]); - - if (pincfg.gpioFun == BFLB_PINMUX_FUN_INST_uart0) { - GLB_UART_Fun_Sel(pincfg.gpioPin % 8, - (BFLB_PINMUX_GET_INST(pins[i])) - * 0x4U /* rts, cts, rx, tx */ - + BFLB_PINMUX_GET_SIGNAL(pins[i]) - ); + for (i = 0U; i < pin_cnt; ++i) { + if (BFLB_PINMUX_GET_FUN(pins[i]) == BFLB_PINMUX_FUN_INST_uart0) { + pinctrl_blfb_configure_uart(BFLB_PINMUX_GET_PIN(pins[i]), + BFLB_PINMUX_GET_SIGNAL(pins[i])); } - GLB_GPIO_Init(&pincfg); + /* gpio init*/ + pinctrl_bflb_init_pin(pins[i]); } return 0; diff --git a/dts/riscv/bouffalolab/bl602.dtsi b/dts/riscv/bouffalolab/bl602.dtsi index bb54598cd65a4..7899a0948c24f 100644 --- a/dts/riscv/bouffalolab/bl602.dtsi +++ b/dts/riscv/bouffalolab/bl602.dtsi @@ -5,3 +5,4 @@ */ #include +#include diff --git a/dts/riscv/bouffalolab/bl604e.dtsi b/dts/riscv/bouffalolab/bl604e.dtsi index 3958721aa9f1a..cfe3c6ab2cc7a 100644 --- a/dts/riscv/bouffalolab/bl604e.dtsi +++ b/dts/riscv/bouffalolab/bl604e.dtsi @@ -5,3 +5,4 @@ */ #include +#include diff --git a/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h b/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h index 6bc371a9b0af4..e3aa44e0f9ba5 100644 --- a/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h +++ b/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h @@ -14,6 +14,7 @@ #include #include +#include /* clang-format off */ diff --git a/soc/bouffalolab/bl60x/CMakeLists.txt b/soc/bouffalolab/bl60x/CMakeLists.txt index f21e11056abb2..07b492a491a5d 100644 --- a/soc/bouffalolab/bl60x/CMakeLists.txt +++ b/soc/bouffalolab/bl60x/CMakeLists.txt @@ -8,4 +8,5 @@ zephyr_sources(soc.c) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") +zephyr_code_relocate_ifdef(CONFIG_PINCTRL_BFLB LIBRARY drivers__pinctrl LOCATION ITCM) zephyr_code_relocate_ifdef(CONFIG_RISCV_MACHINE_TIMER LIBRARY drivers__timer LOCATION ITCM) From dcaf4ebd15de840cfcb14cf94c1be380b19c46e3 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 31 Aug 2024 16:24:46 +0200 Subject: [PATCH 16/21] drivers: gpio: bouffalolab: Add bflb gpio driver Add Bouffalo Lab gpio driver. Signed-off-by: Camille BAUD Signed-off-by: Gerson Fernando Budke --- .../bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml | 1 + .../bl6/bl604e_iot_dvk/doc/index.rst | 2 + drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 1 + drivers/gpio/Kconfig.bflb | 9 + drivers/gpio/gpio_bflb.c | 324 ++++++++++++++++++ dts/bindings/gpio/bflb,bl-gpio.yaml | 22 +- soc/bouffalolab/bl60x/CMakeLists.txt | 1 + 8 files changed, 350 insertions(+), 11 deletions(-) create mode 100644 drivers/gpio/Kconfig.bflb create mode 100644 drivers/gpio/gpio_bflb.c diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml index 7fad6e6d6118f..420f3736ad4f6 100644 --- a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml @@ -14,6 +14,7 @@ testing: - net - bluetooth supported: + - gpio - pinctrl - uart vendor: bflb diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst b/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst index d1ba7a72617c3..795a130ef7d14 100644 --- a/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst +++ b/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst @@ -39,6 +39,8 @@ The board configuration supports the following hardware features: +===========+============+=======================+ | MTIMER | on-chip | RISC-V Machine Timer | +-----------+------------+-----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-----------------------+ | PINCTRL | on-chip | pin muxing | +-----------+------------+-----------------------+ | UART | on-chip | serial port-polling; | diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index dcc4b96a54fa8..d7e121669c1b1 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_AW9523B gpio_aw9523b.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_BFLB gpio_bflb.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) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ba1ed8a3f64be..1f1d04a4114ed 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -105,6 +105,7 @@ source "drivers/gpio/Kconfig.axp192" source "drivers/gpio/Kconfig.b91" source "drivers/gpio/Kconfig.bcm2711" source "drivers/gpio/Kconfig.bd8lb600fs" +source "drivers/gpio/Kconfig.bflb" source "drivers/gpio/Kconfig.brcmstb" source "drivers/gpio/Kconfig.cc13xx_cc26xx" source "drivers/gpio/Kconfig.cc32xx" diff --git a/drivers/gpio/Kconfig.bflb b/drivers/gpio/Kconfig.bflb new file mode 100644 index 0000000000000..c3cf15d66f6f6 --- /dev/null +++ b/drivers/gpio/Kconfig.bflb @@ -0,0 +1,9 @@ +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_BFLB + bool "Bouffalo Lab GPIO driver" + depends on DT_HAS_BFLB_BL_GPIO_ENABLED + default y + help + Bouffalo Lab GPIO driver diff --git a/drivers/gpio/gpio_bflb.c b/drivers/gpio/gpio_bflb.c new file mode 100644 index 0000000000000..152f51e5ee807 --- /dev/null +++ b/drivers/gpio/gpio_bflb.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bflb_bl_gpio + +#include +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(gpio_bflb, CONFIG_GPIO_LOG_LEVEL); + +#define CLEAR_TIMEOUT_COUNTER 32 + +/* clang-format off */ + +struct gpio_bflb_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + uint32_t base_reg; + void (*irq_config_func)(const struct device *dev); + void (*irq_enable_func)(const struct device *dev); +}; + +struct gpio_bflb_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + sys_slist_t callbacks; +}; + +static int gpio_bflb_port_get_raw(const struct device *dev, uint32_t *value) +{ + const struct gpio_bflb_config *const cfg = dev->config; + + *value = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL30_OFFSET); + + return 0; +} + +static int gpio_bflb_port_set_masked_raw(const struct device *dev, + uint32_t mask, + uint32_t value) +{ + const struct gpio_bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + tmp = (tmp & ~mask) | (mask & value); + sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + + return 0; +} + +static int gpio_bflb_port_set_bits_raw(const struct device *dev, uint32_t mask) +{ + const struct gpio_bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + tmp |= mask; + sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + + return 0; +} + +static int gpio_bflb_port_clear_bits_raw(const struct device *dev, uint32_t mask) +{ + const struct gpio_bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + tmp &= ~mask; + sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + + return 0; +} + +static int gpio_bflb_port_toggle_bits(const struct device *dev, uint32_t mask) +{ + const struct gpio_bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + tmp ^= mask; + sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + + return 0; +} + +static void gpio_bflb_port_interrupt_configure_mode(const struct device *dev, + uint32_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + const struct gpio_bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + uint8_t trig_mode = 0; /* default to 'sync' mode */ + + tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MODE_SET1_OFFSET + ((pin / 10) << 2)); + tmp &= ~(0x07 << ((pin % 10) * 3)); /* clear modes */ + + if ((trig & GPIO_INT_HIGH_1) != 0) { + trig_mode |= 1; + } + + if (!(mode & GPIO_INT_EDGE)) { + trig_mode |= 2; + } + + tmp |= (trig_mode << ((pin % 10) * 3)); + sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MODE_SET1_OFFSET + ((pin / 10) << 2)); +} + +static void gpio_bflb_pin_interrupt_clear(const struct device *dev, uint32_t mask) +{ + const struct gpio_bflb_config *const cfg = dev->config; + int32_t timeout = CLEAR_TIMEOUT_COUNTER; + + sys_write32(mask, cfg->base_reg + GLB_GPIO_INT_CLR1_OFFSET); + + while ((sys_read32(cfg->base_reg + GLB_GPIO_INT_STAT1_OFFSET) & mask) != 0 + && timeout > 0) { + --timeout; + } + + sys_write32(0x0, cfg->base_reg + GLB_GPIO_INT_CLR1_OFFSET); +} + +static int gpio_bflb_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + const struct gpio_bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + /* Disable the interrupt. */ + tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET); + tmp |= BIT(pin); + sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET); + + gpio_bflb_port_interrupt_configure_mode(dev, pin, mode, trig); + + if (mode != GPIO_INT_MODE_DISABLED) { + /* clear */ + gpio_bflb_pin_interrupt_clear(dev, BIT(pin)); + + /* unmask */ + tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET); + tmp &= ~BIT(pin); + sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET); + } else { + /* mask */ + tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET); + tmp |= BIT(pin); + sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET); + } + + /* enable clic interrupt for us as it gets cleared in soc init */ + cfg->irq_enable_func(dev); + return 0; +} + +static int gpio_bflb_config(const struct device *dev, gpio_pin_t pin, + gpio_flags_t flags) +{ + const struct gpio_bflb_config *const cfg = dev->config; + uint8_t is_odd = 0; + uint32_t cfg_address; + uint32_t tmp = 0; + uint32_t tmp_a = 0; + uint32_t tmp_b = 0; + + /* Disable output anyway */ + tmp_a = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2)); + tmp_a &= ~(1 << (pin & 0x1f)); + sys_write32(tmp_a, cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2)); + + is_odd = pin & 1; + cfg_address = cfg->base_reg + GLB_GPIO_CFGCTL0_OFFSET + (pin / 2 * 4); + tmp_b = sys_read32(cfg_address); + + tmp_a = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2)); + + if ((flags & GPIO_INPUT) != 0) { + tmp_b |= (1 << (is_odd * 16 + 0)); + tmp_a &= ~(1 << (pin & 0x1f)); + } else { + tmp_b &= ~(1 << (is_odd * 16 + 0)); + } + + if ((flags & GPIO_OUTPUT) != 0) { + tmp_a |= (1 << (pin & 0x1f)); + tmp_b &= ~(1 << (is_odd * 16 + 0)); + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + tmp = tmp | pin; + sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + } + + if (flags & GPIO_OUTPUT_INIT_LOW) { + tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + tmp = tmp & ~pin; + sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET); + } + } else { + tmp_a &= ~(1 << (pin & 0x1f)); + } + + sys_write32(tmp_a, cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2)); + + if ((flags & GPIO_PULL_UP) != 0) { + tmp_b |= (1 << (is_odd * 16 + 4)); + tmp_b &= ~(1 << (is_odd * 16 + 5)); + } else if ((flags & GPIO_PULL_DOWN) != 0) { + tmp_b |= (1 << (is_odd * 16 + 5)); + tmp_b &= ~(1 << (is_odd * 16 + 4)); + } else { + tmp_b &= ~(1 << (is_odd * 16 + 4)); + tmp_b &= ~(1 << (is_odd * 16 + 5)); + } + + /* GPIO mode */ + tmp_b &= ~(0x1f << (is_odd * 16 + 8)); + tmp_b |= (11 << (is_odd * 16 + 8)); + + /* enabled SMT in GPIO mode */ + tmp_b |= (1 << (is_odd * 16 + 1)); + + sys_write32(tmp_b, cfg_address); + + return 0; +} + +static int gpio_bflb_init(const struct device *dev) +{ + const struct gpio_bflb_config *const cfg = dev->config; + + /* nothing to do beside link irq */ + + cfg->irq_config_func(dev); + + return 0; +} + +static void gpio_bflb_isr(const struct device *dev) +{ + const struct gpio_bflb_config *const cfg = dev->config; + struct gpio_bflb_data *data = dev->data; + uint32_t int_stat; + + /* interrupt data is in format 1 bit = 1 pin */ + int_stat = sys_read32(cfg->base_reg + GLB_GPIO_INT_STAT1_OFFSET); + + gpio_fire_callbacks(&data->callbacks, dev, int_stat); + + /* clear interrupts */ + gpio_bflb_pin_interrupt_clear(dev, int_stat); +} + +static int gpio_bflb_manage_callback(const struct device *port, + struct gpio_callback *callback, + bool set) +{ + struct gpio_bflb_data *data = port->data; + + return gpio_manage_callback(&(data->callbacks), callback, set); +} + +static const struct gpio_driver_api gpio_bflb_api = { + .pin_configure = gpio_bflb_config, + .port_get_raw = gpio_bflb_port_get_raw, + .port_set_masked_raw = gpio_bflb_port_set_masked_raw, + .port_set_bits_raw = gpio_bflb_port_set_bits_raw, + .port_clear_bits_raw = gpio_bflb_port_clear_bits_raw, + .port_toggle_bits = gpio_bflb_port_toggle_bits, + .pin_interrupt_configure = gpio_bflb_pin_interrupt_configure, + .manage_callback = gpio_bflb_manage_callback, +}; + +#define GPIO_BFLB_INIT(n) \ + static void port_##n##_bflb_irq_config_func(const struct device *dev); \ + static void port_##n##_bflb_irq_enable_func(const struct device *dev); \ + \ + static const struct gpio_bflb_config port_##n##_bflb_config = { \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .base_reg = DT_INST_REG_ADDR(n), \ + .irq_config_func = port_##n##_bflb_irq_config_func, \ + .irq_enable_func = port_##n##_bflb_irq_enable_func, \ + }; \ + \ + static struct gpio_bflb_data port_##n##_bflb_data; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_bflb_init, NULL, \ + &port_##n##_bflb_data, \ + &port_##n##_bflb_config, PRE_KERNEL_1, \ + CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_bflb_api); \ + \ + static void port_##n##_bflb_irq_config_func(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + gpio_bflb_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + } \ + \ + static void port_##n##_bflb_irq_enable_func(const struct device *dev) \ + { \ + irq_enable(DT_INST_IRQN(n)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(GPIO_BFLB_INIT) + +/* clang-format on */ diff --git a/dts/bindings/gpio/bflb,bl-gpio.yaml b/dts/bindings/gpio/bflb,bl-gpio.yaml index 960eae5d8e17a..3e5ebcc6b2ed7 100644 --- a/dts/bindings/gpio/bflb,bl-gpio.yaml +++ b/dts/bindings/gpio/bflb,bl-gpio.yaml @@ -11,20 +11,20 @@ include: - name: gpio-controller.yaml properties: - reg: - required: true + reg: + required: true - interrupts: - required: true + interrupts: + required: true - "#gpio-cells": - const: 2 + "#gpio-cells": + const: 2 - "#bflb,pin-cells": - type: int - required: true - const: 2 - description: Number of items to expect in a bflb,pins specifier + "#bflb,pin-cells": + type: int + required: true + const: 2 + description: Number of items to expect in a bflb,pins specifier gpio-cells: - pin diff --git a/soc/bouffalolab/bl60x/CMakeLists.txt b/soc/bouffalolab/bl60x/CMakeLists.txt index 07b492a491a5d..89fd5e71a4044 100644 --- a/soc/bouffalolab/bl60x/CMakeLists.txt +++ b/soc/bouffalolab/bl60x/CMakeLists.txt @@ -8,5 +8,6 @@ zephyr_sources(soc.c) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") +zephyr_code_relocate_ifdef(CONFIG_GPIO_BFLB LIBRARY drivers__gpio LOCATION ITCM) zephyr_code_relocate_ifdef(CONFIG_PINCTRL_BFLB LIBRARY drivers__pinctrl LOCATION ITCM) zephyr_code_relocate_ifdef(CONFIG_RISCV_MACHINE_TIMER LIBRARY drivers__timer LOCATION ITCM) From a32c5ce13e2bb04fac83c275e3ed0efcae3b10fc Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 31 Aug 2024 16:06:07 +0200 Subject: [PATCH 17/21] drivers: serial: bouffalolab: Update serial driver Update serial driver to be SDK independent. Signed-off-by: Camille BAUD Signed-off-by: Gerson Fernando Budke --- drivers/serial/Kconfig.bflb | 1 - drivers/serial/uart_bflb.c | 635 +++++++++++++++++++------- dts/bindings/serial/bflb,bl-uart.yaml | 5 - dts/riscv/bouffalolab/bl60x.dtsi | 4 +- soc/bouffalolab/bl60x/CMakeLists.txt | 1 + 5 files changed, 464 insertions(+), 182 deletions(-) diff --git a/drivers/serial/Kconfig.bflb b/drivers/serial/Kconfig.bflb index d619792f99e32..6383a60884c82 100644 --- a/drivers/serial/Kconfig.bflb +++ b/drivers/serial/Kconfig.bflb @@ -8,6 +8,5 @@ config UART_BFLB select PINCTRL select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT - select USE_BFLB_UART help This option enables the UART driver for Bouffalo Lab SoC family. diff --git a/drivers/serial/uart_bflb.c b/drivers/serial/uart_bflb.c index 4cd1a4d67906b..2fc44afdf0cc6 100644 --- a/drivers/serial/uart_bflb.c +++ b/drivers/serial/uart_bflb.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2021-2024 ATL Electronics + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,28 +8,37 @@ #define DT_DRV_COMPAT bflb_bl_uart /** - * @brief UART driver for Bouffalo Lab MCU family. + * @brief UART driver for Bouffalo Lab MCU family */ + #include #include +#include +#include +#include +#include #include -#include -#include -#include -#include -#define UART_CTS_FLOWCONTROL_ENABLE (0) -#define UART_RTS_FLOWCONTROL_ENABLE (0) -#define UART_MSB_FIRST_ENABLE (0) -#define UART_DEFAULT_RTO_TIMEOUT (255) -#define UART_CLOCK_DIV (0) +#include +#include +#include +#include +#include + +/* clang-format off */ struct bflb_config { - uint32_t *reg; - const struct pinctrl_dev_config *pinctrl_cfg; - uint32_t periph_id; - UART_CFG_Type uart_cfg; - UART_FifoCfg_Type fifo_cfg; + const struct pinctrl_dev_config *pincfg; + uint32_t baudrate; + uint8_t direction; + uint8_t data_bits; + uint8_t stop_bits; + uint8_t parity; + uint8_t bit_order; + uint8_t flow_ctrl; + uint8_t tx_fifo_threshold; + uint8_t rx_fifo_threshold; + uint32_t base_reg; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_config_func_t irq_config_func; #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -41,194 +51,290 @@ struct bflb_data { #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; -static int uart_bl_init(const struct device *dev) +static void uart_bflb_enabled(const struct device *dev, uint32_t enable) { const struct bflb_config *cfg = dev->config; + uint32_t rxt = 0; + uint32_t txt = 0; - pinctrl_apply_state(cfg->pinctrl_cfg, PINCTRL_STATE_DEFAULT); - - GLB_Set_UART_CLK(1, HBN_UART_CLK_160M, UART_CLOCK_DIV); - - UART_IntMask(cfg->periph_id, UART_INT_ALL, 1); - UART_Disable(cfg->periph_id, UART_TXRX); - - UART_Init(cfg->periph_id, (UART_CFG_Type *)&cfg->uart_cfg); - UART_TxFreeRun(cfg->periph_id, 1); - UART_SetRxTimeoutValue(cfg->periph_id, UART_DEFAULT_RTO_TIMEOUT); - UART_FifoConfig(cfg->periph_id, (UART_FifoCfg_Type *)&cfg->fifo_cfg); - UART_Enable(cfg->periph_id, UART_TXRX); - -#ifdef CONFIG_UART_INTERRUPT_DRIVEN - cfg->irq_config_func(dev); -#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + if (enable) { + enable = 1; + } - return 0; + txt = sys_read32(cfg->base_reg + UART_UTX_CONFIG_OFFSET); + txt = (txt & ~UART_CR_UTX_EN) | enable; + rxt = sys_read32(cfg->base_reg + UART_URX_CONFIG_OFFSET); + rxt = (rxt & ~UART_CR_URX_EN) | enable; + sys_write32(rxt, cfg->base_reg + UART_URX_CONFIG_OFFSET); + sys_write32(txt, cfg->base_reg + UART_UTX_CONFIG_OFFSET); } -static int uart_bl_poll_in(const struct device *dev, unsigned char *c) +static uint32_t uart_bflb_get_crystal_frequency(void) { - const struct bflb_config *cfg = dev->config; + uint32_t tmp; + + /* get clkpll_sdmin */ + tmp = sys_read32(PDS_BASE + PDS_CLKPLL_SDM_OFFSET); + tmp = (tmp & PDS_CLKPLL_SDMIN_MSK) >> PDS_CLKPLL_SDMIN_POS; + + /* + * The 'Sigma Delta Modulator Input' scales the PLL output relative to the + * input frequency (eg value is x2, output frequency doubles), it's a + * direct indicator of the XCLK (crystal or 32M osc) frequency to go in the + * PLL. + * + * This value can be read from efuse or from the firmware header which will + * be implemented in the future. + */ + switch (tmp) { + case 0x500000: + return MHZ(24); + case 0x3C0000: + return MHZ(32); + case 0x320000: + return MHZ(38.4); + case 0x300000: + return MHZ(40); + case 0x49D39D: + return MHZ(26); + default: + return MHZ(32); + } +} - return UART_ReceiveData(cfg->periph_id, (uint8_t *)c, 1) ? 0 : -1; +static uint32_t uart_bflb_get_pll_frequency(void) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_REG_PLL_SEL_MSK) >> GLB_REG_PLL_SEL_POS; + + if (tmp == 0) { + return MHZ(48); + } else if (tmp == 1) { + return MHZ(120); + } else if (tmp == 2) { + return MHZ(160); + } else if (tmp == 3) { + return MHZ(192); + } else { + return 0; + } } -static void uart_bl_poll_out(const struct device *dev, unsigned char c) +static uint32_t uart_bflb_get_clock(void) { - const struct bflb_config *cfg = dev->config; + uint32_t tmp = 0; + uint32_t uart_divider = 0; + uint32_t hclk_divider = 0; + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG2_OFFSET); + uart_divider = (tmp & GLB_UART_CLK_DIV_MSK) >> GLB_UART_CLK_DIV_POS; + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + tmp = (tmp & HBN_UART_CLK_SEL_MSK) >> HBN_UART_CLK_SEL_POS; + + if (tmp == 0) { + /* FCLK */ + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + hclk_divider = (tmp & GLB_REG_HCLK_DIV_MSK) >> GLB_REG_HCLK_DIV_POS; + + tmp = sys_read32(GLB_BASE + GLB_CLK_CFG0_OFFSET); + tmp = (tmp & GLB_HBN_ROOT_CLK_SEL_MSK) >> GLB_HBN_ROOT_CLK_SEL_POS; + + if (tmp == 0) { + /* RC32M clock */ + tmp = MHZ(32) / (hclk_divider + 1); + return (tmp / (uart_divider + 1)); + } else if (tmp == 1) { + /* Crystal clock */ + tmp = uart_bflb_get_crystal_frequency() + / (hclk_divider + 1); + return (tmp / (uart_divider + 1)); + } else if (tmp > 1) { + /* PLL Clock */ + tmp = uart_bflb_get_pll_frequency() + / (hclk_divider + 1); + return (tmp / (uart_divider + 1)); - while (UART_GetTxFifoCount(cfg->periph_id) == 0) { - ; + } + } else { + /* UART PLL 160 */ + return (MHZ(160) / (uart_divider + 1)); } - - (void)UART_SendData(cfg->periph_id, (uint8_t *)&c, 1); + return 0; } #ifdef CONFIG_UART_INTERRUPT_DRIVEN -static int uart_bl_err_check(const struct device *dev) + +static int uart_bflb_err_check(const struct device *dev) { const struct bflb_config *const cfg = dev->config; - uint32_t status = BL_RD_REG(cfg->reg, UART_INT_STS); - uint32_t tmp = BL_RD_REG(cfg->reg, UART_INT_CLEAR); + uint32_t status = 0; + uint32_t tmp = 0; int errors = 0; - if (status & BIT(UART_INT_RX_FER)) { - tmp |= BIT(UART_INT_RX_FER); + status = sys_read32(cfg->base_reg + UART_INT_STS_OFFSET); + tmp = sys_read32(cfg->base_reg + UART_INT_CLEAR_OFFSET); + if (status & UART_URX_FER_INT) { errors |= UART_ERROR_OVERRUN; } - if (status & BIT(UART_INT_TX_FER)) { - tmp |= BIT(UART_INT_TX_FER); - + if (status & UART_UTX_FER_INT) { errors |= UART_ERROR_OVERRUN; } - if (status & BIT(UART_INT_PCE)) { - tmp |= BIT(UART_INT_PCE); + if (status & UART_URX_PCE_INT) { + tmp |= UART_CR_URX_PCE_CLR; errors |= UART_ERROR_PARITY; } - BL_WR_REG(cfg->reg, UART_INT_CLEAR, tmp); + sys_write32(tmp, cfg->base_reg + UART_INT_CLEAR_OFFSET); return errors; } -int uart_bl_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) +int uart_bflb_irq_tx_ready(const struct device *dev) { const struct bflb_config *const cfg = dev->config; - uint8_t num_tx = 0U; + uint32_t tmp = 0; - while ((len - num_tx > 0) && (UART_GetTxFifoCount(cfg->periph_id) > 0)) { - BL_WR_BYTE(cfg->reg + UART_FIFO_WDATA_OFFSET, tx_data[num_tx++]); - } - - return num_tx; + tmp = sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET); + return (tmp & UART_TX_FIFO_CNT_MASK) > 0; } -int uart_bl_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +int uart_bflb_irq_rx_ready(const struct device *dev) { const struct bflb_config *const cfg = dev->config; - uint8_t num_rx = 0U; - - while ((size - num_rx > 0) && (UART_GetRxFifoCount(cfg->periph_id) > 0)) { - rx_data[num_rx++] = BL_RD_BYTE(cfg->reg + UART_FIFO_RDATA_OFFSET); - } + uint32_t tmp = 0; - return num_rx; + tmp = sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET); + return (tmp & UART_RX_FIFO_CNT_MASK) > 0; } -void uart_bl_irq_tx_enable(const struct device *dev) +int uart_bflb_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) { const struct bflb_config *const cfg = dev->config; + uint8_t num_tx = 0U; + + while (num_tx < len && uart_bflb_irq_tx_ready(dev) > 0) { + sys_write32(tx_data[num_tx++], cfg->base_reg + UART_FIFO_WDATA_OFFSET); + } - UART_IntMask(cfg->periph_id, UART_INT_TX_FIFO_REQ, 1); + return num_tx; } -void uart_bl_irq_tx_disable(const struct device *dev) +int uart_bflb_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) { const struct bflb_config *const cfg = dev->config; + uint8_t num_rx = 0U; - UART_IntMask(cfg->periph_id, UART_INT_TX_FIFO_REQ, 0); + while ((num_rx < size) && uart_bflb_irq_rx_ready(dev) > 0) { + rx_data[num_rx++] = sys_read32(cfg->base_reg + UART_FIFO_RDATA_OFFSET); + } + + return num_rx; } -int uart_bl_irq_tx_ready(const struct device *dev) +void uart_bflb_irq_tx_enable(const struct device *dev) { const struct bflb_config *const cfg = dev->config; - uint32_t maskVal = BL_RD_REG(cfg->reg, UART_INT_MASK); + uint32_t tmp = 0; - return (UART_GetTxFifoCount(cfg->periph_id) > 0) - && BL_IS_REG_BIT_SET(maskVal, UART_CR_UTX_FIFO_MASK); + tmp = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); + tmp = tmp & ~UART_CR_UTX_FIFO_MASK; + sys_write32(tmp, cfg->base_reg + UART_INT_MASK_OFFSET); } -int uart_bl_irq_tx_complete(const struct device *dev) +void uart_bflb_irq_tx_disable(const struct device *dev) { const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; - return !UART_GetTxBusBusyStatus(cfg->periph_id); + tmp = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); + tmp = tmp | UART_CR_UTX_FIFO_MASK; + sys_write32(tmp, cfg->base_reg + UART_INT_MASK_OFFSET); } -void uart_bl_irq_rx_enable(const struct device *dev) +int uart_bflb_irq_tx_complete(const struct device *dev) { const struct bflb_config *const cfg = dev->config; - - UART_IntMask(cfg->periph_id, UART_INT_RX_FIFO_REQ, 1); + uint32_t tmp = 0; + int rc = 0; + + tmp = sys_read32(cfg->base_reg + UART_STATUS_OFFSET); + rc = tmp & UART_STS_UTX_BUS_BUSY; + tmp = sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET); + rc += tmp & UART_TX_FIFO_CNT_MASK; + return (rc > 0 ? 1 : 0); } -void uart_bl_irq_rx_disable(const struct device *dev) +void uart_bflb_irq_rx_enable(const struct device *dev) { const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; - UART_IntMask(cfg->periph_id, UART_INT_RX_FIFO_REQ, 0); + tmp = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); + tmp = tmp & ~UART_CR_URX_FIFO_MASK; + sys_write32(tmp, cfg->base_reg + UART_INT_MASK_OFFSET); } -int uart_bl_irq_rx_ready(const struct device *dev) +void uart_bflb_irq_rx_disable(const struct device *dev) { const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; - return UART_GetRxFifoCount(cfg->periph_id) > 0; + tmp = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); + tmp = tmp | UART_CR_URX_FIFO_MASK; + sys_write32(tmp, cfg->base_reg + UART_INT_MASK_OFFSET); } -void uart_bl_irq_err_enable(const struct device *dev) +void uart_bflb_irq_err_enable(const struct device *dev) { const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; - UART_IntMask(cfg->periph_id, UART_INT_PCE - | UART_INT_TX_FER - | UART_INT_RX_FER, 1); + tmp = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); + tmp = tmp & ~UART_CR_URX_PCE_MASK; + tmp = tmp & ~UART_CR_UTX_FER_MASK; + tmp = tmp & ~UART_CR_URX_FER_MASK; + sys_write32(tmp, cfg->base_reg + UART_INT_MASK_OFFSET); } -void uart_bl_irq_err_disable(const struct device *dev) +void uart_bflb_irq_err_disable(const struct device *dev) { const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; - UART_IntMask(cfg->periph_id, UART_INT_PCE - | UART_INT_TX_FER - | UART_INT_RX_FER, 0); + tmp = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); + tmp = tmp | UART_CR_URX_PCE_MASK; + tmp = tmp | UART_CR_UTX_FER_MASK; + tmp = tmp | UART_CR_URX_FER_MASK; + sys_write32(tmp, cfg->base_reg + UART_INT_MASK_OFFSET); } -int uart_bl_irq_is_pending(const struct device *dev) +int uart_bflb_irq_is_pending(const struct device *dev) { const struct bflb_config *const cfg = dev->config; - uint32_t tmp = BL_RD_REG(cfg->reg, UART_INT_STS); - uint32_t maskVal = BL_RD_REG(cfg->reg, UART_INT_MASK); + uint32_t tmp = sys_read32(cfg->base_reg + UART_INT_STS_OFFSET); + uint32_t maskVal = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); - return ((BL_IS_REG_BIT_SET(tmp, UART_URX_FIFO_INT) && - BL_IS_REG_BIT_SET(maskVal, UART_CR_URX_FIFO_MASK)) || - (BL_IS_REG_BIT_SET(tmp, UART_UTX_FIFO_INT) && - BL_IS_REG_BIT_SET(maskVal, UART_CR_UTX_FIFO_MASK))); + /* only first 8 bits are not reserved */ + return (((tmp & ~maskVal) & 0xFF) != 0 ? 1 : 0); } -int uart_bl_irq_update(const struct device *dev) +int uart_bflb_irq_update(const struct device *dev) { ARG_UNUSED(dev); return 1; } -void uart_bl_irq_callback_set(const struct device *dev, - uart_irq_callback_user_data_t cb, - void *user_data) +void uart_bflb_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data) { struct bflb_data *const data = dev->data; @@ -236,32 +342,216 @@ void uart_bl_irq_callback_set(const struct device *dev, data->user_data = user_data; } -static void uart_bl_isr(const struct device *dev) +static void uart_bflb_isr(const struct device *dev) { struct bflb_data *const data = dev->data; + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; if (data->user_cb) { data->user_cb(dev, data->user_data); } + + /* clear interrupts that require ack*/ + tmp = sys_read32(cfg->base_reg + UART_INT_CLEAR_OFFSET); + tmp = tmp | UART_CR_URX_RTO_CLR; + sys_write32(tmp, cfg->base_reg + UART_INT_CLEAR_OFFSET); +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static int uart_bflb_configure(const struct device *dev) +{ + const struct bflb_config *cfg = dev->config; + uint32_t tx_cfg = 0; + uint32_t rx_cfg = 0; + uint32_t divider = 0; + uint32_t tmp = 0; + + divider = (uart_bflb_get_clock() * 10 / cfg->baudrate + 5) / 10; + if (divider >= 0xFFFF) { + divider = 0xFFFF - 1; + } + + uart_bflb_enabled(dev, 0); + + sys_write32(((divider - 1) << 0x10) | ((divider - 1) & 0xFFFF), + cfg->base_reg + UART_BIT_PRD_OFFSET); + + /* Configure Parity */ + tx_cfg = sys_read32(cfg->base_reg + UART_UTX_CONFIG_OFFSET); + rx_cfg = sys_read32(cfg->base_reg + UART_URX_CONFIG_OFFSET); + + switch (cfg->parity) { + case UART_PARITY_NONE: + tx_cfg &= ~UART_CR_UTX_PRT_EN; + rx_cfg &= ~UART_CR_URX_PRT_EN; + break; + case UART_PARITY_ODD: + tx_cfg |= UART_CR_UTX_PRT_EN; + tx_cfg |= UART_CR_UTX_PRT_SEL; + rx_cfg |= UART_CR_URX_PRT_EN; + rx_cfg |= UART_CR_URX_PRT_SEL; + break; + case UART_PARITY_EVEN: + tx_cfg |= UART_CR_UTX_PRT_EN; + tx_cfg &= ~UART_CR_UTX_PRT_SEL; + rx_cfg |= UART_CR_URX_PRT_EN; + rx_cfg &= ~UART_CR_URX_PRT_SEL; + break; + default: + break; + } + + /* Configure data bits */ + tx_cfg &= ~UART_CR_UTX_BIT_CNT_D_MASK; + tx_cfg |= (cfg->data_bits + 4) << UART_CR_UTX_BIT_CNT_D_SHIFT; + rx_cfg &= ~UART_CR_URX_BIT_CNT_D_MASK; + rx_cfg |= (cfg->data_bits + 4) << UART_CR_URX_BIT_CNT_D_SHIFT; + + /* Configure tx stop bits */ + tx_cfg &= ~UART_CR_UTX_BIT_CNT_P_MASK; + tx_cfg |= cfg->stop_bits << UART_CR_UTX_BIT_CNT_P_SHIFT; + + /* Configure tx cts flow control function */ + if (cfg->flow_ctrl & UART_FLOWCTRL_CTS) { + tx_cfg |= UART_CR_UTX_CTS_EN; + } else { + tx_cfg &= ~UART_CR_UTX_CTS_EN; + } + + /* disable de-glitch function */ + rx_cfg &= ~UART_CR_URX_DEG_EN; + + /* Write config */ + sys_write32(tx_cfg, cfg->base_reg + UART_UTX_CONFIG_OFFSET); + sys_write32(rx_cfg, cfg->base_reg + UART_URX_CONFIG_OFFSET); + + /* enable hardware control RTS */ +#if defined(CONFIG_SOC_SERIES_BL60X) + tmp = sys_read32(cfg->base_reg + UART_URX_CONFIG_OFFSET); + tmp &= ~UART_CR_URX_RTS_SW_MODE; + sys_write32(tmp, cfg->base_reg + UART_URX_CONFIG_OFFSET); +#else + tmp = sys_read32(cfg->base_reg + UART_SW_MODE_OFFSET); + tmp &= ~UART_CR_URX_RTS_SW_MODE; + sys_write32(tmp, cfg->base_reg + UART_SW_MODE_OFFSET); +#endif + + /* disable inversion */ + tmp = sys_read32(cfg->base_reg + UART_DATA_CONFIG_OFFSET); + tmp &= ~UART_CR_UART_BIT_INV; + sys_write32(tmp, cfg->base_reg + UART_DATA_CONFIG_OFFSET); + + + /* TX free run enable */ + tmp = sys_read32(cfg->base_reg + UART_UTX_CONFIG_OFFSET); + tmp |= UART_CR_UTX_FRM_EN; + sys_write32(tmp, cfg->base_reg + UART_UTX_CONFIG_OFFSET); + + + /* Configure FIFO thresholds */ + tmp = sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET); + tmp &= ~UART_TX_FIFO_TH_MASK; + tmp &= ~UART_RX_FIFO_TH_MASK; + tmp |= (cfg->tx_fifo_threshold << UART_TX_FIFO_TH_SHIFT) + & UART_TX_FIFO_TH_MASK; + tmp |= (cfg->rx_fifo_threshold << UART_RX_FIFO_TH_SHIFT) + & UART_RX_FIFO_TH_MASK; + sys_write32(tmp, cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET); + + /* Clear FIFO */ + tmp = sys_read32(cfg->base_reg + UART_FIFO_CONFIG_0_OFFSET); + tmp |= UART_TX_FIFO_CLR; + tmp |= UART_RX_FIFO_CLR; + tmp &= ~UART_DMA_TX_EN; + tmp &= ~UART_DMA_RX_EN; + sys_write32(tmp, cfg->base_reg + UART_FIFO_CONFIG_0_OFFSET); + + return 0; } + +static int uart_bflb_init(const struct device *dev) +{ + const struct bflb_config *cfg = dev->config; + int rc = 0; + + pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); + + rc = uart_bflb_configure(dev); + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + /* disable all irqs */ + sys_write32(0x0, cfg->base_reg + UART_INT_EN_OFFSET); + /* clear all IRQS */ + sys_write32(0xFF, cfg->base_reg + UART_INT_CLEAR_OFFSET); + /* mask all IRQs */ + sys_write32(0xFFFFFFFF, cfg->base_reg + UART_INT_MASK_OFFSET); + /* unmask necessary irqs */ + uart_bflb_irq_rx_enable(dev); + uart_bflb_irq_err_enable(dev); + /* enable all irqs */ + sys_write32(0xFF, cfg->base_reg + UART_INT_EN_OFFSET); + cfg->irq_config_func(dev); #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + uart_bflb_enabled(dev, 1); + + return rc; +} + +static int uart_bflb_poll_in(const struct device *dev, unsigned char *c) +{ + const struct bflb_config *cfg = dev->config; + + if ((sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET) + & UART_RX_FIFO_CNT_MASK) == 0) { + return -1; + } + + *c = sys_read8(cfg->base_reg + UART_FIFO_RDATA_OFFSET); + + return 0; +} + +static void uart_bflb_poll_out(const struct device *dev, unsigned char c) +{ + const struct bflb_config *cfg = dev->config; + + while ((sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET) + & UART_TX_FIFO_CNT_MASK) == 0) { + } + sys_write8(c, cfg->base_reg + UART_FIFO_WDATA_OFFSET); +} #ifdef CONFIG_PM_DEVICE -static int uart_bl_pm_control(const struct device *dev, - enum pm_device_action action) +static int uart_bflb_pm_action(const struct device *dev, + enum pm_device_action action) { const struct bflb_config *cfg = dev->config; + uint32_t tx_cfg; + uint32_t rx_cfg; switch (action) { case PM_DEVICE_ACTION_RESUME: - (void)pinctrl_apply_state(cfg->pinctrl_cfg, PINCTRL_STATE_DEFAULT); - UART_Enable(cfg->periph_id, UART_TXRX); + (void)pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); + + tx_cfg = sys_read32(cfg->base_reg + UART_UTX_CONFIG_OFFSET); + rx_cfg = sys_read32(cfg->base_reg + UART_URX_CONFIG_OFFSET); + tx_cfg |= UART_CR_UTX_EN; + rx_cfg |= UART_CR_URX_EN; + sys_write32(tx_cfg, cfg->base_reg + UART_UTX_CONFIG_OFFSET); + sys_write32(rx_cfg, cfg->base_reg + UART_URX_CONFIG_OFFSET); break; case PM_DEVICE_ACTION_SUSPEND: - if (pinctrl_apply_state(cfg->pinctrl_cfg, PINCTRL_STATE_SLEEP)) { + if (pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_SLEEP)) { return -ENOTSUP; } - UART_Disable(cfg->periph_id, UART_TXRX); + + tx_cfg = sys_read32(cfg->base_reg + UART_UTX_CONFIG_OFFSET); + rx_cfg = sys_read32(cfg->base_reg + UART_URX_CONFIG_OFFSET); + tx_cfg &= ~UART_CR_UTX_EN; + rx_cfg &= ~UART_CR_URX_EN; + sys_write32(tx_cfg, cfg->base_reg + UART_UTX_CONFIG_OFFSET); + sys_write32(rx_cfg, cfg->base_reg + UART_URX_CONFIG_OFFSET); break; default: return -ENOTSUP; @@ -271,83 +561,80 @@ static int uart_bl_pm_control(const struct device *dev, } #endif /* CONFIG_PM_DEVICE */ -static const struct uart_driver_api uart_bl_driver_api = { - .poll_in = uart_bl_poll_in, - .poll_out = uart_bl_poll_out, +static const struct uart_driver_api uart_bflb_driver_api = { + .poll_in = uart_bflb_poll_in, + .poll_out = uart_bflb_poll_out, #ifdef CONFIG_UART_INTERRUPT_DRIVEN - .err_check = uart_bl_err_check, - .fifo_fill = uart_bl_fifo_fill, - .fifo_read = uart_bl_fifo_read, - .irq_tx_enable = uart_bl_irq_tx_enable, - .irq_tx_disable = uart_bl_irq_tx_disable, - .irq_tx_ready = uart_bl_irq_tx_ready, - .irq_tx_complete = uart_bl_irq_tx_complete, - .irq_rx_enable = uart_bl_irq_rx_enable, - .irq_rx_disable = uart_bl_irq_rx_disable, - .irq_rx_ready = uart_bl_irq_rx_ready, - .irq_err_enable = uart_bl_irq_err_enable, - .irq_err_disable = uart_bl_irq_err_disable, - .irq_is_pending = uart_bl_irq_is_pending, - .irq_update = uart_bl_irq_update, - .irq_callback_set = uart_bl_irq_callback_set, + .err_check = uart_bflb_err_check, + .fifo_fill = uart_bflb_fifo_fill, + .fifo_read = uart_bflb_fifo_read, + .irq_tx_enable = uart_bflb_irq_tx_enable, + .irq_tx_disable = uart_bflb_irq_tx_disable, + .irq_tx_ready = uart_bflb_irq_tx_ready, + .irq_tx_complete = uart_bflb_irq_tx_complete, + .irq_rx_enable = uart_bflb_irq_rx_enable, + .irq_rx_disable = uart_bflb_irq_rx_disable, + .irq_rx_ready = uart_bflb_irq_rx_ready, + .irq_err_enable = uart_bflb_irq_err_enable, + .irq_err_disable = uart_bflb_irq_err_disable, + .irq_is_pending = uart_bflb_irq_is_pending, + .irq_update = uart_bflb_irq_update, + .irq_callback_set = uart_bflb_irq_callback_set, #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; #ifdef CONFIG_UART_INTERRUPT_DRIVEN -#define BFLB_UART_IRQ_HANDLER_DECL(n) \ - static void uart_bl_config_func_##n(const struct device *dev); -#define BFLB_UART_IRQ_HANDLER_FUNC(n) \ - .irq_config_func = uart_bl_config_func_##n -#define BFLB_UART_IRQ_HANDLER(n) \ - static void uart_bl_config_func_##n(const struct device *dev) \ +#define BFLB_UART_IRQ_HANDLER_DECL(instance) \ + static void uart_bflb_config_func_##instance(const struct device *dev); +#define BFLB_UART_IRQ_HANDLER_FUNC(instance) \ + .irq_config_func = uart_bflb_config_func_##instance +#define BFLB_UART_IRQ_HANDLER(instance) \ + static void uart_bflb_config_func_##instance(const struct device *dev) \ { \ - IRQ_CONNECT(DT_INST_IRQN(n), \ - DT_INST_IRQ(n, priority), \ - uart_bl_isr, \ - DEVICE_DT_INST_GET(n), \ + IRQ_CONNECT(DT_INST_IRQN(instance), \ + DT_INST_IRQ(instance, priority), \ + uart_bflb_isr, \ + DEVICE_DT_INST_GET(instance), \ 0); \ - irq_enable(DT_INST_IRQN(n)); \ + irq_enable(DT_INST_IRQN(instance)); \ } #else /* CONFIG_UART_INTERRUPT_DRIVEN */ -#define BFLB_UART_IRQ_HANDLER_DECL(n) -#define BFLB_UART_IRQ_HANDLER_FUNC(n) -#define BFLB_UART_IRQ_HANDLER(n) +#define BFLB_UART_IRQ_HANDLER_DECL(instance) +#define BFLB_UART_IRQ_HANDLER_FUNC(instance) +#define BFLB_UART_IRQ_HANDLER(instance) #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ -#define BFLB_UART_INIT(n) \ - PINCTRL_DT_INST_DEFINE(n); \ +#define BL_UART_INIT(instance) \ + PINCTRL_DT_INST_DEFINE(instance); \ + PM_DEVICE_DT_INST_DEFINE(instance, uart_bflb_pm_action); \ + BFLB_UART_IRQ_HANDLER_DECL(instance) \ \ - BFLB_UART_IRQ_HANDLER_DECL(n) \ + static struct bflb_data uart##instance##_bflb_data; \ \ - static struct bflb_data uart##n##_bl_data; \ - static const struct bflb_config uart##n##_bl_config = { \ - .reg = (uint32_t *)DT_INST_REG_ADDR(n), \ - .pinctrl_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ - .periph_id = DT_INST_PROP(n, peripheral_id), \ - \ - .uart_cfg.baudRate = DT_INST_PROP(n, current_speed), \ - .uart_cfg.dataBits = UART_DATABITS_8, \ - .uart_cfg.stopBits = UART_STOPBITS_1, \ - .uart_cfg.parity = UART_PARITY_NONE, \ - .uart_cfg.uartClk = SOC_BOUFFALOLAB_BL_PLL160_FREQ_HZ, \ - .uart_cfg.ctsFlowControl = UART_CTS_FLOWCONTROL_ENABLE, \ - .uart_cfg.rtsSoftwareControl = UART_RTS_FLOWCONTROL_ENABLE, \ - .uart_cfg.byteBitInverse = UART_MSB_FIRST_ENABLE, \ - \ - .fifo_cfg.txFifoDmaThreshold = 1, \ - .fifo_cfg.rxFifoDmaThreshold = 1, \ - .fifo_cfg.txFifoDmaEnable = 0, \ - .fifo_cfg.rxFifoDmaEnable = 0, \ - \ - BFLB_UART_IRQ_HANDLER_FUNC(n) \ + static const struct bflb_config uart##instance##_bflb_config = { \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(instance), \ + .base_reg = DT_INST_REG_ADDR(instance), \ + .baudrate = DT_INST_PROP(instance, current_speed), \ + .data_bits = UART_DATA_BITS_8, \ + .stop_bits = UART_STOP_BITS_1, \ + .parity = UART_PARITY_NONE, \ + .bit_order = UART_MSB_FIRST, \ + .flow_ctrl = UART_FLOWCTRL_NONE, \ + /* overflow interrupt threshold, size is 32 bytes*/ \ + .tx_fifo_threshold = 8, \ + .rx_fifo_threshold = 0, \ + BFLB_UART_IRQ_HANDLER_FUNC(instance) \ }; \ - DEVICE_DT_INST_DEFINE(n, &uart_bl_init, \ - uart_bl_pm_control, \ - &uart##n##_bl_data, \ - &uart##n##_bl_config, PRE_KERNEL_1, \ - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ - &uart_bl_driver_api); \ \ - BFLB_UART_IRQ_HANDLER(n) + DEVICE_DT_INST_DEFINE(instance, &uart_bflb_init, \ + PM_DEVICE_DT_INST_GET(instance), \ + &uart##instance##_bflb_data, \ + &uart##instance##_bflb_config, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_bflb_driver_api); \ + \ + BFLB_UART_IRQ_HANDLER(instance) + +DT_INST_FOREACH_STATUS_OKAY(BL_UART_INIT) -DT_INST_FOREACH_STATUS_OKAY(BFLB_UART_INIT) +/* clang-format on */ diff --git a/dts/bindings/serial/bflb,bl-uart.yaml b/dts/bindings/serial/bflb,bl-uart.yaml index 8e2c67ea208c5..dc248673127cf 100644 --- a/dts/bindings/serial/bflb,bl-uart.yaml +++ b/dts/bindings/serial/bflb,bl-uart.yaml @@ -13,8 +13,3 @@ include: properties: reg: required: true - - peripheral-id: - type: int - description: peripheral ID - required: true diff --git a/dts/riscv/bouffalolab/bl60x.dtsi b/dts/riscv/bouffalolab/bl60x.dtsi index 8056084b05adb..7af0bd223262c 100644 --- a/dts/riscv/bouffalolab/bl60x.dtsi +++ b/dts/riscv/bouffalolab/bl60x.dtsi @@ -119,14 +119,14 @@ uart0: uart@4000a000 { compatible = "bflb,bl-uart"; reg = <0x4000a000 0x100>; - interrupts = <29 0>; + interrupts = <45 0>; interrupt-parent = <&clic>; status = "disabled"; }; uart1: uart@4000a100 { compatible = "bflb,bl-uart"; reg = <0x4000a100 0x100>; - interrupts = <30 0>; + interrupts = <46 0>; interrupt-parent = <&clic>; status = "disabled"; }; diff --git a/soc/bouffalolab/bl60x/CMakeLists.txt b/soc/bouffalolab/bl60x/CMakeLists.txt index 89fd5e71a4044..91930a78450dd 100644 --- a/soc/bouffalolab/bl60x/CMakeLists.txt +++ b/soc/bouffalolab/bl60x/CMakeLists.txt @@ -11,3 +11,4 @@ set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld zephyr_code_relocate_ifdef(CONFIG_GPIO_BFLB LIBRARY drivers__gpio LOCATION ITCM) zephyr_code_relocate_ifdef(CONFIG_PINCTRL_BFLB LIBRARY drivers__pinctrl LOCATION ITCM) zephyr_code_relocate_ifdef(CONFIG_RISCV_MACHINE_TIMER LIBRARY drivers__timer LOCATION ITCM) +zephyr_code_relocate_ifdef(CONFIG_UART_BFLB LIBRARY drivers__serial LOCATION ITCM) From 317329444ae460c719d0c955a99ba74d97b570ef Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 31 Aug 2024 16:29:32 +0200 Subject: [PATCH 18/21] scripts: runner: Introduce bflb_mcu_tool runner Add Bouffalo Lab ISP console flash runner. This tool enable bootloader to flash devices using serial port. The blflash Rust tool can be found at https://pypi.org/project/bflb-mcu-tool Signed-off-by: Camille BAUD Signed-off-by: Gerson Fernando Budke --- boards/common/bflb_mcu_tool.board.cmake | 4 + scripts/west_commands/runners/__init__.py | 1 + .../west_commands/runners/bflb_mcu_tool.py | 89 +++++++++++++++++++ scripts/west_commands/tests/test_imports.py | 1 + 4 files changed, 95 insertions(+) create mode 100644 boards/common/bflb_mcu_tool.board.cmake create mode 100644 scripts/west_commands/runners/bflb_mcu_tool.py diff --git a/boards/common/bflb_mcu_tool.board.cmake b/boards/common/bflb_mcu_tool.board.cmake new file mode 100644 index 0000000000000..73862b0f5e195 --- /dev/null +++ b/boards/common/bflb_mcu_tool.board.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(bflb_mcu_tool) +board_finalize_runner_args(bflb_mcu_tool) diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index cd7be7f92d0fc..4f772548892be 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -26,6 +26,7 @@ def _import_runner_module(runner_name): _names = [ # zephyr-keep-sorted-start + 'bflb_mcu_tool', 'blackmagicprobe', 'blflash', 'bossac', diff --git a/scripts/west_commands/runners/bflb_mcu_tool.py b/scripts/west_commands/runners/bflb_mcu_tool.py new file mode 100644 index 0000000000000..534af9f2abd37 --- /dev/null +++ b/scripts/west_commands/runners/bflb_mcu_tool.py @@ -0,0 +1,89 @@ +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for the Official Bouffalo Lab open source command-line flash tool (bflb-mcu-tool)''' + +import shutil + +from runners.core import RunnerCaps, ZephyrBinaryRunner + +DEFAULT_PORT = '/dev/ttyUSB0' +DEFAULT_SPEED = '115200' +DEFAULT_CHIP = 'bl602' +BFLB_SDK_MODULE_NAME = 'hal_bouffalolab' +DEFAULT_EXECUTABLE = "bflb-mcu-tool" + + +class BlFlashCommandBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for bflb-mcu-tool.''' + + def __init__( + self, cfg, port=DEFAULT_PORT, baudrate=DEFAULT_SPEED, chipname=DEFAULT_CHIP, erase=False + ): + super().__init__(cfg) + self.port = port + self.baudrate = baudrate + self.chipname = chipname + self.erase = bool(erase) + + @classmethod + def name(cls): + return 'bflb_mcu_tool' + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={'flash'}, erase=True) + + @classmethod + def do_add_parser(cls, parser): + parser.add_argument( + '-p', + '--port', + default=DEFAULT_PORT, + help='serial port to use, default is ' + str(DEFAULT_PORT), + ) + parser.add_argument( + '-b', + '--baudrate', + default=DEFAULT_SPEED, + help='serial port speed to use, default is ' + DEFAULT_SPEED, + ) + parser.add_argument( + '-ch', + '--chipname', + default=DEFAULT_CHIP, + help='chip model, default is ' + DEFAULT_CHIP, + choices=['bl602', 'bl606p', 'bl616', 'bl702', 'bl702l', 'bl808'], + ) + + @classmethod + def do_create(cls, cfg, args): + print(args) + if shutil.which(DEFAULT_EXECUTABLE) is None: + raise ValueError( + "Couldnt find bflb-mcu-tool in PATH, please install with pip install \ +bflb-mcu-tool" + ) + return BlFlashCommandBinaryRunner( + cfg, port=args.port, baudrate=args.baudrate, chipname=args.chipname, erase=args.erase + ) + + def do_run(self, command, **kwargs): + self.ensure_output('bin') + cmd_flash = [ + DEFAULT_EXECUTABLE, + '--interface', + 'uart', + '--port', + self.port, + '--baudrate', + self.baudrate, + '--chipname', + self.chipname, + '--firmware', + self.cfg.bin_file, + ] + if self.erase is True: + cmd_flash.append("--erase") + self.check_call(cmd_flash) diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 66874b18902c1..7dcc154725763 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -17,6 +17,7 @@ def test_runner_imports(): expected = set(( # zephyr-keep-sorted-start 'arc-nsim', + 'bflb_mcu_tool', 'blackmagicprobe', 'blflash', 'bossac', From a699d4fb3c8f689f44751e49c9e465b99035e13d Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 9 Sep 2024 17:19:19 +0200 Subject: [PATCH 19/21] boards: riscv: bl604e_iot_dvk: Move to bl60x directory Move the board to the new SoC directory. Signed-off-by: Gerson Fernando Budke --- .../bl604e_iot_dvk/Kconfig.bl604e_iot_dvk | 0 .../bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi | 0 .../bl604e_iot_dvk/bl604e_iot_dvk.dts | 0 .../bl604e_iot_dvk/bl604e_iot_dvk.yaml | 0 .../bl604e_iot_dvk/bl604e_iot_dvk_defconfig | 0 .../{bl6 => bl60x}/bl604e_iot_dvk/board.cmake | 0 .../{bl6 => bl60x}/bl604e_iot_dvk/board.yml | 0 .../bl604e_iot_dvk/doc/img/bl_604e.jpg | Bin .../{bl6 => bl60x}/bl604e_iot_dvk/doc/index.rst | 0 .../{bl6 => bl60x}/bl604e_iot_dvk/support/bl6.cfg | 0 .../bl604e_iot_dvk/support/openocd.cfg | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/bl604e_iot_dvk.dts (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/bl604e_iot_dvk.yaml (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/bl604e_iot_dvk_defconfig (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/board.cmake (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/board.yml (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/doc/img/bl_604e.jpg (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/doc/index.rst (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/support/bl6.cfg (100%) rename boards/bouffalolab/{bl6 => bl60x}/bl604e_iot_dvk/support/openocd.cfg (100%) diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk b/boards/bouffalolab/bl60x/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.dts b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.dts similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.dts rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.dts diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk_defconfig b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk_defconfig similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk_defconfig rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk_defconfig diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/board.cmake b/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/board.cmake rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/board.yml b/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.yml similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/board.yml rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/board.yml diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/img/bl_604e.jpg b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/img/bl_604e.jpg similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/doc/img/bl_604e.jpg rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/img/bl_604e.jpg diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/support/bl6.cfg b/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/bl6.cfg similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/support/bl6.cfg rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/support/bl6.cfg diff --git a/boards/bouffalolab/bl6/bl604e_iot_dvk/support/openocd.cfg b/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/openocd.cfg similarity index 100% rename from boards/bouffalolab/bl6/bl604e_iot_dvk/support/openocd.cfg rename to boards/bouffalolab/bl60x/bl604e_iot_dvk/support/openocd.cfg From 5613e368ccfee29b0db4228c3e05b2ac1a574420 Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Mon, 9 Sep 2024 17:21:01 +0200 Subject: [PATCH 20/21] scripts: runner: Drop blflash in favor of bflb_mcu_tool Use official flash tool by default. Signed-off-by: Gerson Fernando Budke --- .../bl60x/bl604e_iot_dvk/board.cmake | 6 +- .../bl60x/bl604e_iot_dvk/doc/index.rst | 59 ++----------------- boards/common/blflash.board.cmake | 4 -- scripts/west_commands/runners/__init__.py | 1 - scripts/west_commands/runners/blflash.py | 59 ------------------- scripts/west_commands/tests/test_imports.py | 1 - 6 files changed, 10 insertions(+), 120 deletions(-) delete mode 100644 boards/common/blflash.board.cmake delete mode 100644 scripts/west_commands/runners/blflash.py diff --git a/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake b/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake index f9d962c35327c..bdf0d1a10833d 100644 --- a/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake +++ b/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake @@ -19,5 +19,7 @@ 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(blflash --port /dev/ttyACM0) -include(${ZEPHYR_BASE}/boards/common/blflash.board.cmake) +board_runner_args(bflb_mcu_tool --chipname bl602) +include(${ZEPHYR_BASE}/boards/common/bflb_mcu_tool.board.cmake) + +board_set_flasher(bflb_mcu_tool) diff --git a/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst index 795a130ef7d14..514b7d9f269d8 100644 --- a/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst +++ b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst @@ -49,7 +49,7 @@ The board configuration supports the following hardware features: The default configurations can be found in the Kconfig -:zephyr_file:`boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk_defconfig`. +:zephyr_file:`boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk_defconfig`. System Clock ============ @@ -66,53 +66,6 @@ USB Serial converter and port is used for both program and console. Programming and Debugging ************************* -BL Flash tool -============= - -The BL-60x have a ROM bootloader that allows user flash device by serial port. -There are some tools available at internet and this will describe one of them. -The below guide was created based on RISC-V BL602 Book, chapter 3 -`Flashing Firmware to BL602`_. - -#. `Install Rustup`_ - -#. Install cargo - - .. code-block:: console - - $ sudo apt-get install cargo - -#. Clone blflash rust version - - .. code-block:: console - - $ git clone --recursive https://github.com/spacemeowx2/blflash - -#. Build blflash - - .. code-block:: console - - $ cd blflash - $ cargo build --release - -#. Install blflash. The recommended use is copy to home folder - - .. code-block:: console - - $ cp target/release/blflash ~/bin/ - -#. Test - - .. code-block:: console - - $ blflash -V - - It will print blflash version - - .. code-block:: console - - $ blflash 0.3.5 - Samples ======= @@ -125,7 +78,7 @@ application: :goals: build :compact: -#. To flash an image using blflash runner: +#. To flash an image using bflb_mcu_tool runner: #. Press BOOT button @@ -135,7 +88,7 @@ application: .. code-block:: console - west flash -r blflash + west flash #. Run your favorite terminal program to listen for output. Under Linux the terminal should be :code:`/dev/ttyACM0`. For example: @@ -159,6 +112,9 @@ application: *** Booting Zephyr OS build v3.7.0-3255-g6e0fa5c1c77a *** Hello World! bl604e_iot_dvk/bl604e20q2i + +To debug the board you can use ``west debug`` command with OpenOCD. + Congratulations, you have ``bl604e_iot_dvk`` configured and running Zephyr. @@ -171,9 +127,6 @@ Congratulations, you have ``bl604e_iot_dvk`` configured and running Zephyr. .. _Bouffalo Lab Development Zone: https://dev.bouffalolab.com/home?id=guest -.. _Install Rustup: - https://rustup.rs/ - .. _The RISC-V BL602 Book: https://lupyuen.github.io/articles/book diff --git a/boards/common/blflash.board.cmake b/boards/common/blflash.board.cmake deleted file mode 100644 index 5c99a2b913bf1..0000000000000 --- a/boards/common/blflash.board.cmake +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -board_set_flasher_ifnset(blflash) -board_finalize_runner_args(blflash) diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index 4f772548892be..881c06efa092d 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -28,7 +28,6 @@ def _import_runner_module(runner_name): # zephyr-keep-sorted-start 'bflb_mcu_tool', 'blackmagicprobe', - 'blflash', 'bossac', 'canopen_program', 'dediprog', diff --git a/scripts/west_commands/runners/blflash.py b/scripts/west_commands/runners/blflash.py deleted file mode 100644 index 0fca611b2f6e9..0000000000000 --- a/scripts/west_commands/runners/blflash.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2021 Gerson Fernando Budke -# -# SPDX-License-Identifier: Apache-2.0 - -'''Bouffalo Lab flash tool (blflash) runner for serial boot ROM''' - -from runners.core import ZephyrBinaryRunner, RunnerCaps - -DEFAULT_BLFLASH_PORT = '/dev/ttyUSB0' -DEFAULT_BLFLASH_SPEED = '2000000' - -class BlFlashBinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for blflash.''' - - def __init__(self, cfg, blflash='blflash', - port=DEFAULT_BLFLASH_PORT, - speed=DEFAULT_BLFLASH_SPEED): - super().__init__(cfg) - self.blflash = blflash - self.port = port - self.speed = speed - - @classmethod - def name(cls): - return 'blflash' - - @classmethod - def capabilities(cls): - return RunnerCaps(commands={'flash'}) - - @classmethod - def do_add_parser(cls, parser): - parser.add_argument('--blflash', default='blflash', - help='path to blflash, default is blflash') - parser.add_argument('--port', default=DEFAULT_BLFLASH_PORT, - help='serial port to use, default is ' + - str(DEFAULT_BLFLASH_PORT)) - parser.add_argument('--speed', default=DEFAULT_BLFLASH_SPEED, - help='serial port speed to use, default is ' + - DEFAULT_BLFLASH_SPEED) - - @classmethod - def do_create(cls, cfg, args): - return BlFlashBinaryRunner(cfg, - blflash=args.blflash, - port=args.port, - speed=args.speed) - - def do_run(self, command, **kwargs): - self.require(self.blflash) - self.ensure_output('bin') - - cmd_flash = [self.blflash, - 'flash', - self.cfg.bin_file, - '-p', self.port, - '-b', self.speed] - - self.check_call(cmd_flash) diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 7dcc154725763..7b6126d3d3cb6 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -19,7 +19,6 @@ def test_runner_imports(): 'arc-nsim', 'bflb_mcu_tool', 'blackmagicprobe', - 'blflash', 'bossac', 'canopen', 'dediprog', From 6cfc4204e318b7d7505a6817177d49748ae3931f Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Sat, 21 Sep 2024 18:09:14 +0200 Subject: [PATCH 21/21] MAINTAINERS.yml: Add Bouffalo Lab entries Introduce Bouffalo Lab platform. Signed-off-by: Gerson Fernando Budke --- MAINTAINERS.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c0c4fe5c556c6..bf084f79d5023 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3446,6 +3446,21 @@ ADI Platforms: labels: - "platform: ADI" +Bouffalolab Platforms: + status: maintained + maintainers: + - nandojve + files: + - boards/bouffalolab/ + - boards/common/*bflb* + - drivers/*/*bflb* + - dts/riscv/bouffalolab/ + - dts/bindings/*/bflb,* + - scripts/west_commands/*/*bflb* + - soc/bouffalolab/ + labels: + - "platform: bouffalolab" + Broadcom Platforms: status: odd fixes files: @@ -4760,6 +4775,16 @@ West: labels: - "platform: Microchip SAM" +"West project: hal_bouffalolab": + status: maintained + maintainers: + - nandojve + files: + - modules/Kconfig.bouffalolab + - modules/hal_bouffalolab/ + labels: + - "platform: Bouffalo Lab" + "West project: hal_cypress": status: maintained maintainers: