diff --git a/boards/aithinker/ai_m62_12f/Kconfig.ai_m62_12f b/boards/aithinker/ai_m62_12f/Kconfig.ai_m62_12f new file mode 100644 index 0000000000000..5e2c09e47c490 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/Kconfig.ai_m62_12f @@ -0,0 +1,6 @@ +# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_AI_M62_12F + select SOC_BL616C50Q2I diff --git a/boards/aithinker/ai_m62_12f/ai_m62_12f-pinctrl.dtsi b/boards/aithinker/ai_m62_12f/ai_m62_12f-pinctrl.dtsi new file mode 100644 index 0000000000000..7fdb06f5ddca4 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/ai_m62_12f-pinctrl.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) + * + * 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/aithinker/ai_m62_12f/ai_m62_12f.dts b/boards/aithinker/ai_m62_12f/ai_m62_12f.dts new file mode 100644 index 0000000000000..9801310d9c292 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/ai_m62_12f.dts @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "ai_m62_12f-pinctrl.dtsi" + +/ { + model = "Ai-Thinker M62-12F development board"; + compatible = "bflb,bl616"; + + chosen { + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,itcm = &sram1; + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&flashctrl { + flash0: flash@A0000000 { + compatible = "soc-nv-flash", "gd,25lq32d"; + reg = <0xA0000000 (0x400000 - 0x2000)>; + write-block-size = <256>; + erase-block-size = ; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x00000000 0x00100000>; + read-only; + }; + + storage_partition: partition@100000 { + label = "storage"; + reg = <0x00100000 (0x300000 - 0x2000)>; + }; + }; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/aithinker/ai_m62_12f/ai_m62_12f.yaml b/boards/aithinker/ai_m62_12f/ai_m62_12f.yaml new file mode 100644 index 0000000000000..8556256541faf --- /dev/null +++ b/boards/aithinker/ai_m62_12f/ai_m62_12f.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +identifier: ai_m62_12f +name: Ai-Thinker M62-12F development board +type: mcu +arch: riscv +ram: 480 +toolchain: + - zephyr +testing: + ignore_tags: + - net + - bluetooth +supported: + - pinctrl + - uart +vendor: bflb diff --git a/boards/aithinker/ai_m62_12f/ai_m62_12f_defconfig b/boards/aithinker/ai_m62_12f/ai_m62_12f_defconfig new file mode 100644 index 0000000000000..7836442f7c45d --- /dev/null +++ b/boards/aithinker/ai_m62_12f/ai_m62_12f_defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y + +CONFIG_UART_CONSOLE=y diff --git a/boards/aithinker/ai_m62_12f/board.cmake b/boards/aithinker/ai_m62_12f/board.cmake new file mode 100644 index 0000000000000..dd5219e96b902 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/board.cmake @@ -0,0 +1,23 @@ +# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(openocd --cmd-pre-init "source [find bl61x.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 0x22FC0000 0x23010000 rw") +board_runner_args(openocd --gdb-init "mem 0x62FC0000 0x63010000 rw") +board_runner_args(openocd --gdb-init "mem 0x90000000 0x90020000 ro") +board_runner_args(openocd --gdb-init "mem 0xA8000000 0xA8800000 rw") +board_runner_args(openocd --gdb-init "mem 0xA0000000 0xA0400000 ro") +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) + +board_runner_args(bflb_mcu_tool --chipname bl616) +include(${ZEPHYR_BASE}/boards/common/bflb_mcu_tool.board.cmake) + +board_set_flasher(bflb_mcu_tool) diff --git a/boards/aithinker/ai_m62_12f/board.yml b/boards/aithinker/ai_m62_12f/board.yml new file mode 100644 index 0000000000000..447e1750cfb82 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/board.yml @@ -0,0 +1,6 @@ +board: + name: ai_m62_12f + full_name: Ai-Thinker M62-12F development board + vendor: aithinker + socs: + - name: bl616c50q2i diff --git a/boards/aithinker/ai_m62_12f/doc/img/ai_m62_12f.webp b/boards/aithinker/ai_m62_12f/doc/img/ai_m62_12f.webp new file mode 100644 index 0000000000000..c7873d796ef6e Binary files /dev/null and b/boards/aithinker/ai_m62_12f/doc/img/ai_m62_12f.webp differ diff --git a/boards/aithinker/ai_m62_12f/doc/index.rst b/boards/aithinker/ai_m62_12f/doc/index.rst new file mode 100644 index 0000000000000..f8ee171718a32 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/doc/index.rst @@ -0,0 +1,84 @@ +.. zephyr:board:: ai_m62_12f + +Overview +******** + +Ai-M62-12F is a Wi-Fi 6 + BLE5.3 module developed by Shenzhen Ai-Thinker Technology +Co., Ltd. The module is equipped with BL616 chip as the core processor, supports Wi-Fi +802.11b/g/n/ax protocol and BLE protocol, and supports Thread protocol. The BL616 system +includes a low-power 32-bit RISC-V CPU with floating-point unit, DSP unit, cache and +memory, with a maximum dominant frequency of 320M. + +Hardware +******** + +For more information about the Bouffalo Lab BL-60x MCU: + +- `Bouffalo Lab BL61x MCU Datasheet`_ +- `Bouffalo Lab Development Zone`_ +- `ai_m62_12f Schematics`_ + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +System Clock +============ + +The WB2 (BL602) Development Board is configured to run at max speed (192MHz). + +Serial Port +=========== + +The ``ai_m62_12f`` board uses UART0 as default serial port. It is connected +to USB Serial converter and port is used for both program and console. + + +Programming and Debugging +************************* + +Samples +======= + +#. Build the Zephyr kernel and the :zephyr:code-sample:`hello_world` sample +application: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: ai_m62_12f + :goals: build flash + +#. Run your favorite terminal program to listen for output. Under Linux the + terminal should be :code:`/dev/ttyUSB0`. For example: + + .. code-block:: console + + $ screen /dev/ttyUSB0 115200 + + The -o option tells minicom not to send the modem initialization + string. Connection should be configured as follows: + + - Speed: 115200 + - Data: 8 bits + - Parity: None + - Stop bits: 1 + + Then, press and release RST button + + .. code-block:: console + + *** Booting Zephyr OS build v4.2.0 *** + Hello World! ai_m62_12f/bl616c50q2i + +Congratulations, you have ``ai_m62_12f`` configured and running Zephyr. + + +.. _Bouffalo Lab BL61x MCU Datasheet: + https://github.com/bouffalolab/bl_docs/tree/main/BL616_DS/en + +.. _Bouffalo Lab Development Zone: + https://dev.bouffalolab.com/home?id=guest + +.. _ai_m62_12f Schematics: + https://docs.ai-thinker.com/en/ai_m62/ diff --git a/boards/aithinker/ai_m62_12f/support/bl61x.cfg b/boards/aithinker/ai_m62_12f/support/bl61x.cfg new file mode 100644 index 0000000000000..9c8523db4f1d8 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/support/bl61x.cfg @@ -0,0 +1,80 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME riscv +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +if { [info exists WORKAREAADDR] } { + set _WORKAREAADDR $WORKAREAADDR +} else { + set _WORKAREAADDR 0x40000000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x10000b6f +} + +transport select jtag +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME + +$_TARGETNAME.0 configure -work-area-phys $_WORKAREAADDR -work-area-size $_WORKAREASIZE -work-area-backup 0 + +echo "Ready for Remote Connections" + +$_TARGETNAME.0 configure -event reset-assert-pre { + echo "reset-assert-pre" + adapter speed 400 +} + +$_TARGETNAME.0 configure -event reset-deassert-post { + echo "reset-deassert-post" + + adapter speed 400 + + reg mstatus 0x7880 + reg mie 0 +} + +$_TARGETNAME.0 configure -event reset-init { + echo "reset-init" + + adapter speed 400 + reg mstatus 0x1880 + reg mie 0 + reg pc 0xA0000000 +} + +$_TARGETNAME.0 configure -event gdb-attach { + echo "Debugger attaching: halting execution" + halt + gdb_breakpoint_override hard +} + +$_TARGETNAME.0 configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +gdb_memory_map enable +gdb_flash_program enable + +# 'progbuf', 'sysbus' or 'abstract' +riscv set_mem_access sysbus +riscv set_command_timeout_sec 1 + +init diff --git a/boards/aithinker/ai_m62_12f/support/openocd.cfg b/boards/aithinker/ai_m62_12f/support/openocd.cfg new file mode 100644 index 0000000000000..ea9daa4d8b525 --- /dev/null +++ b/boards/aithinker/ai_m62_12f/support/openocd.cfg @@ -0,0 +1,5 @@ +# For WCH linkE in DAP mode + +interface cmsis-dap + +adapter speed 400 diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 1e7c3873c043a..47f4efe1a3944 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -61,6 +61,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL clock_con zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X clock_control_bl61x.c) if(CONFIG_CLOCK_CONTROL_RENESAS_RZA2M_CPG) zephyr_library_sources(clock_control_renesas_rza2m_cpg.c) diff --git a/drivers/clock_control/Kconfig.bflb b/drivers/clock_control/Kconfig.bflb index dd89dbdf4f804..4dd346fa269c8 100644 --- a/drivers/clock_control/Kconfig.bflb +++ b/drivers/clock_control/Kconfig.bflb @@ -5,3 +5,8 @@ config CLOCK_CONTROL_BOUFFALOLAB_BL60X bool "Bouffalolab BL60x Clock Control" default y depends on DT_HAS_BFLB_BL60X_CLOCK_CONTROLLER_ENABLED + +config CLOCK_CONTROL_BOUFFALOLAB_BL61X + bool "Bouffalolab BL61x Clock Control Driver" + default y + depends on DT_HAS_BFLB_BL61X_CLOCK_CONTROLLER_ENABLED diff --git a/drivers/clock_control/clock_control_bl61x.c b/drivers/clock_control/clock_control_bl61x.c new file mode 100644 index 0000000000000..f6e7f0b81b76e --- /dev/null +++ b/drivers/clock_control/clock_control_bl61x.c @@ -0,0 +1,1299 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bflb_bl61x_clock_controller + +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(clock_control_bl61x, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLK_SRC_IS(clk, src) \ + DT_SAME_NODE(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), 0), \ + DT_INST_CLOCKS_CTLR_BY_NAME(0, src)) + +#define CLOCK_TIMEOUT 1024 +#define EFUSE_RC32M_TRIM_OFFSET 0x7C +#define EFUSE_RC32M_TRIM_EP_OFFSET 0x78 +#define EFUSE_RC32M_TRIM_EP_EN_POS 1 +#define EFUSE_RC32M_TRIM_EP_PARITY_POS 0 +#define EFUSE_RC32M_TRIM_POS 4 +#define EFUSE_RC32M_TRIM_MSK 0xFF0 + +#define CRYSTAL_ID_FREQ_32000000 0 +#define CRYSTAL_ID_FREQ_24000000 1 +#define CRYSTAL_ID_FREQ_38400000 2 +#define CRYSTAL_ID_FREQ_40000000 3 +#define CRYSTAL_ID_FREQ_26000000 4 + +#define CRYSTAL_FREQ_TO_ID(freq) CONCAT(CRYSTAL_ID_FREQ_, freq) + +enum bl61x_clkid { + bl61x_clkid_clk_root = BL61X_CLKID_CLK_ROOT, + bl61x_clkid_clk_rc32m = BL61X_CLKID_CLK_RC32M, + bl61x_clkid_clk_crystal = BL61X_CLKID_CLK_CRYSTAL, + bl61x_clkid_clk_wifipll = BL61X_CLKID_CLK_WIFIPLL, + bl61x_clkid_clk_aupll = BL61X_CLKID_CLK_AUPLL, + bl61x_clkid_clk_bclk = BL61X_CLKID_CLK_BCLK, +}; + +struct clock_control_bl61x_pll_config { + enum bl61x_clkid source; + bool overclock; +}; + +struct clock_control_bl61x_root_config { + enum bl61x_clkid source; + uint8_t pll_select; + uint8_t divider; +}; + +struct clock_control_bl61x_bclk_config { + uint8_t divider; +}; + +struct clock_control_bl61x_flashclk_config { + enum bl61x_clkid source; + uint8_t divider; + uint8_t bank1_read_delay; + bool bank1_clock_invert; + bool bank1_rx_clock_invert; +}; + +struct clock_control_bl61x_config { + uint32_t crystal_id; +}; + +struct clock_control_bl61x_data { + bool crystal_enabled; + bool wifipll_enabled; + bool aupll_enabled; + struct clock_control_bl61x_pll_config wifipll; + struct clock_control_bl61x_pll_config aupll; + struct clock_control_bl61x_root_config root; + struct clock_control_bl61x_bclk_config bclk; + struct clock_control_bl61x_flashclk_config flashclk; +}; + +typedef struct { + uint8_t pllRefdivRatio; + uint8_t pllIntFracSw; + uint8_t pllIcp1u; + uint8_t pllIcp5u; + uint8_t pllRz; + uint8_t pllCz; + uint8_t pllC3; + uint8_t pllR4Short; + uint8_t pllC4En; + uint8_t pllSelSampleClk; + uint8_t pllVcoSpeed; + uint8_t pllSdmCtrlHw; + uint8_t pllSdmBypass; + uint32_t pllSdmin; + uint8_t aupllPostDiv; +} bl61x_pll_config; + +/* XCLK is 32M */ +static const bl61x_pll_config wifipll_32M = { + .pllRefdivRatio = 2, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x1E00000, + .aupllPostDiv = 0, +}; + +/* XCLK is 38.4M */ +static const bl61x_pll_config wifipll_38P4M = { + .pllRefdivRatio = 2, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x1900000, + .aupllPostDiv = 0, +}; + +/* XCLK is 40M */ +static const bl61x_pll_config wifipll_40M = { + .pllRefdivRatio = 2, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x1800000, + .aupllPostDiv = 0, +}; + +/* XCLK is 24M */ +static const bl61x_pll_config wifipll_24M = { + .pllRefdivRatio = 1, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x1400000, + .aupllPostDiv = 0, +}; + +/* XCLK is 26M */ +static const bl61x_pll_config wifipll_26M = { + .pllRefdivRatio = 1, + .pllIntFracSw = 1, + .pllIcp1u = 1, + .pllIcp5u = 0, + .pllRz = 5, + .pllCz = 2, + .pllC3 = 2, + .pllR4Short = 0, + .pllC4En = 1, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 0, + .pllSdmBypass = 0, + .pllSdmin = 0x1276276, + .aupllPostDiv = 0, +}; + +static const bl61x_pll_config wifipll_32M_O480M = { + .pllRefdivRatio = 2, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x2D00000, + .aupllPostDiv = 0, +}; + +static const bl61x_pll_config wifipll_40M_O480M = { + .pllRefdivRatio = 2, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x2400000, + .aupllPostDiv = 0, +}; + +static const bl61x_pll_config wifipll_38P4M_O480M = { + .pllRefdivRatio = 2, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x2580000, + .aupllPostDiv = 0, +}; + +static const bl61x_pll_config wifipll_24M_O480M = { + .pllRefdivRatio = 1, + .pllIntFracSw = 0, + .pllIcp1u = 0, + .pllIcp5u = 2, + .pllRz = 3, + .pllCz = 1, + .pllC3 = 2, + .pllR4Short = 1, + .pllC4En = 0, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 1, + .pllSdmBypass = 1, + .pllSdmin = 0x1E00000, + .aupllPostDiv = 0, +}; + +static const bl61x_pll_config wifipll_26M_O480M = { + .pllRefdivRatio = 1, + .pllIntFracSw = 1, + .pllIcp1u = 1, + .pllIcp5u = 0, + .pllRz = 5, + .pllCz = 2, + .pllC3 = 2, + .pllR4Short = 0, + .pllC4En = 1, + .pllSelSampleClk = 1, + .pllVcoSpeed = 5, + .pllSdmCtrlHw = 0, + .pllSdmBypass = 0, + .pllSdmin = 0x1BB13B1, + .aupllPostDiv = 0, +}; + +static const bl61x_pll_config *const bl61x_pll_configs[6] = { +&wifipll_32M, &wifipll_24M, &wifipll_38P4M, &wifipll_40M, &wifipll_26M +}; + + +static const bl61x_pll_config *const bl61x_pll_configs_O480M[6] = { +&wifipll_32M_O480M, &wifipll_24M_O480M, &wifipll_38P4M_O480M, &wifipll_40M_O480M, &wifipll_26M_O480M +}; + +/* this imagines we are at 320M clock */ +static void clock_control_bl61x_clock_at_least_us(uint32_t us) +{ + for (uint32_t i = 0; i < us * 32; i++) { + clock_bflb_settle(); + } +} + +static int clock_control_bl61x_deinit_crystal(void) +{ + uint32_t tmp; + + /* power crystal */ + tmp = sys_read32(AON_BASE + AON_RF_TOP_AON_OFFSET); + tmp = tmp & AON_PU_XTAL_AON_UMSK; + tmp = tmp & AON_PU_XTAL_BUF_AON_UMSK; + sys_write32(tmp, AON_BASE + AON_RF_TOP_AON_OFFSET); + + clock_bflb_settle(); + return 0; +} + +static int clock_control_bl61x_init_crystal(void) +{ + uint32_t tmp; + int count = CLOCK_TIMEOUT; + + /* power crystal */ + tmp = sys_read32(AON_BASE + AON_RF_TOP_AON_OFFSET); + tmp = (tmp & AON_PU_XTAL_AON_UMSK) | (1U << AON_PU_XTAL_AON_POS); + tmp = (tmp & AON_PU_XTAL_BUF_AON_UMSK) | (1U << AON_PU_XTAL_BUF_AON_POS); + sys_write32(tmp, AON_BASE + AON_RF_TOP_AON_OFFSET); + + /* wait for crystal to be powered on */ + do { + clock_bflb_settle(); + tmp = sys_read32(AON_BASE + AON_TSEN_OFFSET); + count--; + } while (!(tmp & AON_XTAL_RDY_MSK) && count > 0); + + clock_bflb_settle(); + if (count < 1) { + return -1; + } + return 0; +} + +/* /!\ on bl61x hclk is only for CLIC + * FCLK is the core clock + */ +static int clock_bflb_set_root_clock_dividers(uint32_t hclk_div, uint32_t bclk_div) +{ + uint32_t tmp; + uint32_t old_rootclk; + int count = CLOCK_TIMEOUT; + + old_rootclk = clock_bflb_get_root_clock(); + + /* security RC32M */ + if (old_rootclk > 1) { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_RC32M); + } + + /* set dividers */ + tmp = sys_read32(GLB_BASE + GLB_SYS_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_SYS_CFG0_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_SYS_CFG1_OFFSET); + tmp = (tmp & GLB_REG_BCLK_DIV_ACT_PULSE_UMSK) | (1 << GLB_REG_BCLK_DIV_ACT_PULSE_POS); + sys_write32(tmp, GLB_BASE + GLB_SYS_CFG1_OFFSET); + + + do { + tmp = sys_read32(GLB_BASE + GLB_SYS_CFG1_OFFSET); + tmp &= GLB_STS_BCLK_PROT_DONE_MSK; + tmp = tmp >> GLB_STS_BCLK_PROT_DONE_POS; + count--; + } while (count > 0 && tmp == 0); + + clock_bflb_set_root_clock(old_rootclk); + clock_bflb_settle(); + + if (count < 1) { + return -EIO; + } + + return 0; +} + +static void clock_control_bl61x_set_machine_timer_clock_enable(bool enable) +{ + uint32_t tmp; + + tmp = sys_read32(MCU_MISC_BASE + MCU_MISC_MCU_E907_RTC_OFFSET); + if (enable) { + tmp = (tmp & MCU_MISC_REG_MCU_RTC_EN_UMSK) | (1U << MCU_MISC_REG_MCU_RTC_EN_POS); + } else { + tmp = (tmp & MCU_MISC_REG_MCU_RTC_EN_UMSK) | (0U << MCU_MISC_REG_MCU_RTC_EN_POS); + } + sys_write32(tmp, MCU_MISC_BASE + MCU_MISC_MCU_E907_RTC_OFFSET); +} + +/* source_clock: + * 0: XCLK (RC32M or XTAL) + * 1: Root Clock (FCLK: RC32M, XTAL or PLLs) + */ +static void clock_control_bl61x_set_machine_timer_clock(bool enable, uint32_t source_clock, + uint32_t divider) +{ + uint32_t tmp; + + if (source_clock > 1) { + source_clock = 0; + } + + tmp = sys_read32(MCU_MISC_BASE + MCU_MISC_MCU_E907_RTC_OFFSET); + tmp = (tmp & MCU_MISC_REG_MCU_RTC_CLK_SEL_UMSK) + | (source_clock << MCU_MISC_REG_MCU_RTC_CLK_SEL_POS); + sys_write32(tmp, MCU_MISC_BASE + MCU_MISC_MCU_E907_RTC_OFFSET); + + /* disable first, then set div */ + clock_control_bl61x_set_machine_timer_clock_enable(false); + + tmp = sys_read32(MCU_MISC_BASE + MCU_MISC_MCU_E907_RTC_OFFSET); + tmp = (tmp & MCU_MISC_REG_MCU_RTC_DIV_UMSK) + | ((divider & 0x3FF) << MCU_MISC_REG_MCU_RTC_DIV_POS); + sys_write32(tmp, MCU_MISC_BASE + MCU_MISC_MCU_E907_RTC_OFFSET); + + clock_control_bl61x_set_machine_timer_clock_enable(enable); +} + +static void clock_control_bl61x_deinit_wifipll(void) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp &= GLB_PU_WIFIPLL_UMSK; + tmp &= GLB_PU_WIFIPLL_SFREG_UMSK; + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); +} + +/* RC32M : 0 + * XTAL : 1 + */ +static void clock_control_bl61x_set_wifipll_source(uint32_t source) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG1_OFFSET); + if (source == 1) { + tmp = (tmp & GLB_WIFIPLL_REFCLK_SEL_UMSK) | (1U << GLB_WIFIPLL_REFCLK_SEL_POS); + } else { + tmp = (tmp & GLB_WIFIPLL_REFCLK_SEL_UMSK) | (3U << GLB_WIFIPLL_REFCLK_SEL_POS); + } + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG1_OFFSET); +} + +static void clock_control_bl61x_init_wifipll_setup(const bl61x_pll_config *const config, + bool overclock) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG1_OFFSET); + tmp = (tmp & GLB_WIFIPLL_REFDIV_RATIO_UMSK) + | (config->pllRefdivRatio << GLB_WIFIPLL_REFDIV_RATIO_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG1_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG2_OFFSET); + tmp = (tmp & GLB_WIFIPLL_INT_FRAC_SW_UMSK) + | (config->pllIntFracSw << GLB_WIFIPLL_INT_FRAC_SW_POS); + tmp = (tmp & GLB_WIFIPLL_ICP_1U_UMSK) + | (config->pllIcp1u << GLB_WIFIPLL_ICP_1U_POS); + tmp = (tmp & GLB_WIFIPLL_ICP_5U_UMSK) + | (config->pllIcp5u << GLB_WIFIPLL_ICP_5U_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG2_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG3_OFFSET); + tmp = (tmp & GLB_WIFIPLL_RZ_UMSK) + | (config->pllRz << GLB_WIFIPLL_RZ_POS); + tmp = (tmp & GLB_WIFIPLL_CZ_UMSK) + | (config->pllCz << GLB_WIFIPLL_CZ_POS); + tmp = (tmp & GLB_WIFIPLL_C3_UMSK) + | (config->pllC3 << GLB_WIFIPLL_C3_POS); + tmp = (tmp & GLB_WIFIPLL_R4_SHORT_UMSK) + | (config->pllR4Short << GLB_WIFIPLL_R4_SHORT_POS); + tmp = (tmp & GLB_WIFIPLL_C4_EN_UMSK) + | (config->pllC4En << GLB_WIFIPLL_C4_EN_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG3_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG4_OFFSET); + tmp = (tmp & GLB_WIFIPLL_SEL_SAMPLE_CLK_UMSK) + | (config->pllSelSampleClk << GLB_WIFIPLL_SEL_SAMPLE_CLK_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG4_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG5_OFFSET); + tmp = (tmp & GLB_WIFIPLL_VCO_SPEED_UMSK) + | (config->pllVcoSpeed << GLB_WIFIPLL_VCO_SPEED_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG5_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG6_OFFSET); + tmp = (tmp & GLB_WIFIPLL_SDM_CTRL_HW_UMSK) + | (config->pllSdmCtrlHw << GLB_WIFIPLL_SDM_CTRL_HW_POS); + tmp = (tmp & GLB_WIFIPLL_SDM_BYPASS_UMSK) + | (config->pllSdmBypass << GLB_WIFIPLL_SDM_BYPASS_POS); + tmp = (tmp & GLB_WIFIPLL_SDMIN_UMSK) + | (config->pllSdmin << GLB_WIFIPLL_SDMIN_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG6_OFFSET); + + /* We need to overclock those as well for USB to work for some reason */ + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG10_OFFSET); + if (overclock) { + tmp = (tmp & GLB_USBPLL_SDMIN_UMSK) + | (0x3C000 << GLB_USBPLL_SDMIN_POS); + } else { + tmp = (tmp & GLB_USBPLL_SDMIN_UMSK) + | (0x28000 << GLB_USBPLL_SDMIN_POS); + } + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG10_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG12_OFFSET); + if (overclock) { + tmp = (tmp & GLB_SSCDIV_SDMIN_UMSK) + | (0x3C000 << GLB_SSCDIV_SDMIN_POS); + } else { + tmp = (tmp & GLB_SSCDIV_SDMIN_UMSK) + | (0x28000 << GLB_SSCDIV_SDMIN_POS); + } + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG12_OFFSET); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_PU_WIFIPLL_SFREG_UMSK) + | (1 << GLB_PU_WIFIPLL_SFREG_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + + clock_control_bl61x_clock_at_least_us(8); + + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_PU_WIFIPLL_UMSK) + | (1 << GLB_PU_WIFIPLL_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + + clock_control_bl61x_clock_at_least_us(8); + + /* 'SDM reset' */ + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_WIFIPLL_SDM_RSTB_UMSK) + | (1 << GLB_WIFIPLL_SDM_RSTB_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + clock_control_bl61x_clock_at_least_us(8); + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_WIFIPLL_SDM_RSTB_UMSK) + | (0 << GLB_WIFIPLL_SDM_RSTB_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + clock_control_bl61x_clock_at_least_us(8); + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_WIFIPLL_SDM_RSTB_UMSK) + | (1 << GLB_WIFIPLL_SDM_RSTB_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + + /* 'pll reset' */ + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_WIFIPLL_FBDV_RSTB_UMSK) + | (1 << GLB_WIFIPLL_FBDV_RSTB_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + clock_control_bl61x_clock_at_least_us(8); + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_WIFIPLL_FBDV_RSTB_UMSK) + | (0 << GLB_WIFIPLL_FBDV_RSTB_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + clock_control_bl61x_clock_at_least_us(8); + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + tmp = (tmp & GLB_WIFIPLL_FBDV_RSTB_UMSK) + | (1 << GLB_WIFIPLL_FBDV_RSTB_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG0_OFFSET); + + /* enable PLL outputs */ + tmp = sys_read32(GLB_BASE + GLB_WIFI_PLL_CFG8_OFFSET); + tmp = (tmp & GLB_WIFIPLL_EN_DIV3_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV3_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV4_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV4_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV5_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV5_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV6_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV6_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV8_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV8_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV10_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV10_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV12_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV12_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV20_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV20_POS); + tmp = (tmp & GLB_WIFIPLL_EN_DIV30_UMSK) + | (1 << GLB_WIFIPLL_EN_DIV30_POS); + sys_write32(tmp, GLB_BASE + GLB_WIFI_PLL_CFG8_OFFSET); + + clock_control_bl61x_clock_at_least_us(50); +} + +static void clock_control_bl61x_init_wifipll(const bl61x_pll_config *const *config, + enum bl61x_clkid source, uint32_t crystal_id) +{ + uint32_t tmp; + uint32_t old_rootclk = 0; + + old_rootclk = clock_bflb_get_root_clock(); + + /* security RC32M */ + if (old_rootclk > 1) { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_RC32M); + } + + + clock_control_bl61x_deinit_wifipll(); + + if (source == BL61X_CLKID_CLK_CRYSTAL) { + clock_control_bl61x_set_wifipll_source(1); + if (config == bl61x_pll_configs_O480M) { + clock_control_bl61x_init_wifipll_setup(config[crystal_id], true); + } else { + clock_control_bl61x_init_wifipll_setup(config[crystal_id], false); + } + } else { + clock_control_bl61x_set_wifipll_source(0); + clock_control_bl61x_init_wifipll_setup(config[CRYSTAL_ID_FREQ_32000000], false); + } + + /* enable PLL clock */ + tmp = sys_read32(GLB_BASE + GLB_SYS_CFG0_OFFSET); + tmp |= GLB_REG_PLL_EN_MSK; + sys_write32(tmp, GLB_BASE + GLB_SYS_CFG0_OFFSET); + + clock_bflb_set_root_clock(old_rootclk); + clock_bflb_settle(); +} + +/* + * AUPLL DIV1: 1 + * AUPLL DIV2: 0 + * WIFIPLL 240Mhz: 2 + * WIFIPLL 320Mhz: 3 + */ +static void clock_control_bl61x_select_PLL(uint8_t pll) +{ + uint32_t tmp; + + tmp = sys_read32(PDS_BASE + PDS_CPU_CORE_CFG1_OFFSET); + tmp = (tmp & PDS_REG_PLL_SEL_UMSK) | (pll << PDS_REG_PLL_SEL_POS); + sys_write32(tmp, PDS_BASE + PDS_CPU_CORE_CFG1_OFFSET); +} + +/* 'just for safe' + * ISP WIFIPLL 80M : 2 + * ISP AUPLL DIV5 : 3 + * ISP AUPLL DIV6 : 4 + * TOP AUPLL DIV5 : 5 + * TOP AUPLL DIV6 : 6 + * PSRAMB WIFIPLL 320M : 7 + * PSRAMB AUPLL DIV1 : 8 + * TOP WIFIPLL 240M : 13 + * TOP WIFIPLL 320M : 14 + * TOP AUPLL DIV2 : 15 + * TOP AUPLL DIV1 : 16 + */ +static void clock_control_bl61x_ungate_pll(uint8_t pll) +{ + uint32_t tmp; + + tmp = sys_read32(PDS_BASE + GLB_CGEN_CFG3_OFFSET); + tmp |= (1 << pll); + sys_write32(tmp, PDS_BASE + GLB_CGEN_CFG3_OFFSET); +} + +static int clock_control_bl61x_clock_trim_32M(void) +{ + uint32_t tmp; + uint32_t trim, trim_ep; + int err; + const struct device *efuse = DEVICE_DT_GET_ONE(bflb_efuse); + + + err = syscon_read_reg(efuse, EFUSE_RC32M_TRIM_OFFSET, &trim); + if (err < 0) { + LOG_ERR("Error: Couldn't read efuses: err: %d.\n", err); + return err; + } + err = syscon_read_reg(efuse, EFUSE_RC32M_TRIM_EP_OFFSET, &trim_ep); + if (err < 0) { + LOG_ERR("Error: Couldn't read efuses: err: %d.\n", err); + return err; + } + if (!((trim_ep >> EFUSE_RC32M_TRIM_EP_EN_POS) & 1)) { + LOG_ERR("RC32M trim disabled!"); + return -EINVAL; + } + + trim = (trim & EFUSE_RC32M_TRIM_MSK) >> EFUSE_RC32M_TRIM_POS; + + if (((trim_ep >> EFUSE_RC32M_TRIM_EP_PARITY_POS) & 1) != (POPCOUNT(trim) & 1)) { + LOG_ERR("Bad trim parity"); + return -EINVAL; + } + + tmp = sys_read32(PDS_BASE + PDS_RC32M_CTRL0_OFFSET); + tmp = (tmp & PDS_RC32M_EXT_CODE_EN_UMSK) | 1 << PDS_RC32M_EXT_CODE_EN_POS; + sys_write32(tmp, PDS_BASE + PDS_RC32M_CTRL0_OFFSET); + clock_bflb_settle(); + + tmp = sys_read32(PDS_BASE + PDS_RC32M_CTRL2_OFFSET); + tmp = (tmp & PDS_RC32M_CODE_FR_EXT2_UMSK) | trim << PDS_RC32M_CODE_FR_EXT2_POS; + sys_write32(tmp, PDS_BASE + PDS_RC32M_CTRL2_OFFSET); + + tmp = sys_read32(PDS_BASE + PDS_RC32M_CTRL2_OFFSET); + tmp = (tmp & PDS_RC32M_EXT_CODE_SEL_UMSK) | 1 << PDS_RC32M_EXT_CODE_SEL_POS; + sys_write32(tmp, PDS_BASE + PDS_RC32M_CTRL2_OFFSET); + clock_bflb_settle(); + + return 0; +} + +/* source for most clocks, either XTAL or RC32M */ +static uint32_t clock_control_bl61x_get_xclk(const struct device *dev) +{ + uint32_t tmp; + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + tmp &= HBN_ROOT_CLK_SEL_MSK; + tmp = tmp >> HBN_ROOT_CLK_SEL_POS; + tmp &= 1; + if (tmp == 0) { + return BFLB_RC32M_FREQUENCY; + } else if (tmp == 1) { + return DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), clock_frequency); + } else { + return 0; + } +} + +static uint32_t clock_control_bl61x_mtimer_get_xclk_src_div(const struct device *dev) +{ + return (clock_control_bl61x_get_xclk(dev) / 1000 / 1000 - 1); +} + +/* Almost always CPU, AXI bus, SRAM Memory, Cache, use HCLK query instead */ +static uint32_t clock_control_bl61x_get_fclk(const struct device *dev) +{ + struct clock_control_bl61x_data *data = dev->data; + uint32_t tmp; + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + tmp &= HBN_ROOT_CLK_SEL_MSK; + tmp = (tmp >> HBN_ROOT_CLK_SEL_POS) >> 1; + tmp &= 1; + + if (tmp == 0) { + return clock_control_bl61x_get_xclk(dev); + } + tmp = sys_read32(PDS_BASE + PDS_CPU_CORE_CFG1_OFFSET); + tmp = (tmp & PDS_REG_PLL_SEL_MSK) >> PDS_REG_PLL_SEL_POS; + if (tmp == 3) { + if (data->wifipll.overclock) { + return MHZ(480); + } else { + return MHZ(320); + } + } else if (tmp == 2) { + if (data->wifipll.overclock) { + return MHZ(360); + } else { + return MHZ(240); + } + } else if (tmp == 1) { + /* TODO AUPLL DIV 1 */ + } else if (tmp == 0) { + /* TODO AUPLL DIV 2 */ + } else { + return 0; + } + return 0; +} + +/* CLIC, should be same as FCLK ideally */ +static uint32_t clock_control_bl61x_get_hclk(const struct device *dev) +{ + uint32_t tmp; + uint32_t clock_f; + + tmp = sys_read32(GLB_BASE + GLB_SYS_CFG0_OFFSET); + tmp = (tmp & GLB_REG_HCLK_DIV_MSK) >> GLB_REG_HCLK_DIV_POS; + clock_f = clock_control_bl61x_get_fclk(dev); + return clock_f / (tmp + 1); +} + +/* most peripherals clock */ +static uint32_t clock_control_bl61x_get_bclk(const struct device *dev) +{ + uint32_t tmp; + uint32_t source_clock; + + tmp = sys_read32(GLB_BASE + GLB_SYS_CFG0_OFFSET); + tmp = (tmp & GLB_REG_BCLK_DIV_MSK) >> GLB_REG_BCLK_DIV_POS; + source_clock = clock_control_bl61x_get_hclk(dev); + return source_clock / (tmp + 1); +} + +static void clock_control_bl61x_init_root_as_wifipll(const struct device *dev) +{ + struct clock_control_bl61x_data *data = dev->data; + const struct clock_control_bl61x_config *config = dev->config; + + if (data->wifipll.overclock) { + clock_control_bl61x_init_wifipll(bl61x_pll_configs_O480M, + data->wifipll.source, config->crystal_id); + } else { + clock_control_bl61x_init_wifipll(bl61x_pll_configs, + data->wifipll.source, config->crystal_id); + } + + clock_control_bl61x_select_PLL(data->root.pll_select); + + /* 2T rom access goes here */ + + if (data->root.pll_select == 1) { + clock_control_bl61x_ungate_pll(14); + } else if (data->root.pll_select == 2) { + clock_control_bl61x_ungate_pll(13); + } + + if (data->wifipll.source == bl61x_clkid_clk_crystal) { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_PLL_XTAL); + } else { + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_PLL_RC32M); + } +} + +static void clock_control_bl61x_init_root_as_crystal(const struct device *dev) +{ + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_XTAL); +} + +static __ramfunc void clock_control_bl61x_update_flash_clk(const struct device *dev) +{ + struct clock_control_bl61x_data *data = dev->data; + uint32_t tmp; + + tmp = *(uint32_t *)(GLB_BASE + GLB_SF_CFG0_OFFSET); + tmp &= GLB_SF_CLK_DIV_UMSK; + tmp &= GLB_SF_CLK_EN_UMSK; + tmp |= (data->flashclk.divider - 1) << GLB_SF_CLK_DIV_POS; + *(uint32_t *)(GLB_BASE + GLB_SF_CFG0_OFFSET) = tmp; + + tmp = *(uint32_t *)(SF_CTRL_BASE + SF_CTRL_0_OFFSET); + tmp |= SF_CTRL_SF_IF_READ_DLY_EN_MSK; + tmp &= ~SF_CTRL_SF_IF_READ_DLY_N_MSK; + tmp |= (data->flashclk.bank1_read_delay << SF_CTRL_SF_IF_READ_DLY_N_POS); + if (data->flashclk.bank1_clock_invert) { + tmp &= ~SF_CTRL_SF_CLK_OUT_INV_SEL_MSK; + } else { + tmp |= SF_CTRL_SF_CLK_OUT_INV_SEL_MSK; + } + if (data->flashclk.bank1_rx_clock_invert) { + tmp |= SF_CTRL_SF_CLK_SF_RX_INV_SEL_MSK; + } else { + tmp &= ~SF_CTRL_SF_CLK_SF_RX_INV_SEL_MSK; + } + *(uint32_t *)(SF_CTRL_BASE + SF_CTRL_0_OFFSET) = tmp; + + tmp = *(uint32_t *)(GLB_BASE + GLB_SF_CFG0_OFFSET); + tmp &= GLB_SF_CLK_SEL_UMSK; + tmp &= GLB_SF_CLK_SEL2_UMSK; + if (data->flashclk.source == bl61x_clkid_clk_wifipll) { + tmp |= 0U << GLB_SF_CLK_SEL_POS; + tmp |= 0U << GLB_SF_CLK_SEL_POS; + } else if (data->flashclk.source == bl61x_clkid_clk_crystal) { + tmp |= 0U << GLB_SF_CLK_SEL_POS; + tmp |= 1U << GLB_SF_CLK_SEL2_POS; + } else { + /* If using RC32M or BCLK, use BCLK */ + tmp |= 2U << GLB_SF_CLK_SEL_POS; + } + + *(uint32_t *)(GLB_BASE + GLB_SF_CFG0_OFFSET) = tmp; + + tmp = *(uint32_t *)(GLB_BASE + GLB_SF_CFG0_OFFSET); + tmp |= GLB_SF_CLK_EN_MSK; + *(uint32_t *)(GLB_BASE + GLB_SF_CFG0_OFFSET) = tmp; + + clock_bflb_settle(); +} + +static int clock_control_bl61x_update_root(const struct device *dev) +{ + struct clock_control_bl61x_data *data = dev->data; + uint32_t tmp; + int ret; + + /* make sure all clocks are enabled */ + tmp = sys_read32(GLB_BASE + GLB_SYS_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_SYS_CFG0_OFFSET); + + /* set root clock to internal 32MHz Oscillator as failsafe */ + clock_bflb_set_root_clock(BFLB_MAIN_CLOCK_RC32M); + if (clock_bflb_set_root_clock_dividers(0, 0) != 0) { + return -EIO; + } + + if (data->crystal_enabled) { + if (clock_control_bl61x_init_crystal() < 0) { + return -EIO; + } + } else { + clock_control_bl61x_deinit_crystal(); + } + + ret = clock_bflb_set_root_clock_dividers(data->root.divider - 1, data->bclk.divider - 1); + if (ret < 0) { + return ret; + } + + if (data->root.source == bl61x_clkid_clk_wifipll) { + clock_control_bl61x_init_root_as_wifipll(dev); + } else if (data->root.source == bl61x_clkid_clk_crystal) { + clock_control_bl61x_init_root_as_crystal(dev); + clock_control_bl61x_deinit_wifipll(); + } else { + clock_control_bl61x_deinit_wifipll(); + } + + ret = clock_control_bl61x_clock_trim_32M(); + if (ret < 0) { + return ret; + } + clock_control_bl61x_set_machine_timer_clock( + 1, 0, clock_control_bl61x_mtimer_get_xclk_src_div(dev)); + + clock_bflb_settle(); + + return ret; +} + +static void clock_control_bl61x_uart_set_clock_enable(bool enable) +{ + uint32_t tmp; + + tmp = sys_read32(GLB_BASE + GLB_UART_CFG0_OFFSET); + if (enable) { + tmp = (tmp & GLB_UART_CLK_EN_UMSK) | (1U << GLB_UART_CLK_EN_POS); + } else { + tmp = (tmp & GLB_UART_CLK_EN_UMSK) | (0U << GLB_UART_CLK_EN_POS); + } + sys_write32(tmp, GLB_BASE + GLB_UART_CFG0_OFFSET); +} + +/* Clock: + * BCLK: 0 + * 160 Mhz PLL: 1 + * XCLK: 2 + */ +static void clock_control_bl61x_uart_set_clock(bool enable, uint32_t source_clock, uint32_t divider) +{ + uint32_t tmp; + + if (divider > 0x7) { + divider = 0x7; + } + if (source_clock > 2) { + source_clock = 2; + } + /* disable uart clock */ + clock_control_bl61x_uart_set_clock_enable(false); + + + tmp = sys_read32(GLB_BASE + GLB_UART_CFG0_OFFSET); + tmp = (tmp & GLB_UART_CLK_DIV_UMSK) | (divider << GLB_UART_CLK_DIV_POS); + sys_write32(tmp, GLB_BASE + GLB_UART_CFG0_OFFSET); + + tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); + if (source_clock < 2) { + tmp = (tmp & HBN_UART_CLK_SEL_UMSK) | (source_clock << HBN_UART_CLK_SEL_POS); + tmp = (tmp & HBN_UART_CLK_SEL2_UMSK) | (0U << HBN_UART_CLK_SEL2_POS); + } else { + tmp = (tmp & HBN_UART_CLK_SEL_UMSK) | (0U << HBN_UART_CLK_SEL_POS); + tmp = (tmp & HBN_UART_CLK_SEL2_UMSK) | (1U << HBN_UART_CLK_SEL2_POS); + } + sys_write32(tmp, HBN_BASE + HBN_GLB_OFFSET); + + clock_control_bl61x_uart_set_clock_enable(enable); +} + +/* Simple function to enable all peripherals for now */ +static void clock_control_bl61x_peripheral_clock_init(void) +{ + uint32_t regval = sys_read32(GLB_BASE + GLB_CGEN_CFG1_OFFSET); + + /* enable ADC clock routing */ + regval |= (1 << 2); + /* enable UART0 clock routing */ + regval |= (1 << 16); + /* enable UART1 clock routing */ + regval |= (1 << 17); + /* enable I2C0 clock routing */ + regval |= (1 << 19); + /* enable I2C1 clock routing */ + regval |= (1 << 25); + /* enable SPI0 clock routing */ + regval |= (1 << 18); + /* enable USB clock routing */ + regval |= (1 << 13); + + sys_write32(regval, GLB_BASE + GLB_CGEN_CFG1_OFFSET); + + clock_control_bl61x_uart_set_clock(1, 0, 2); +} + +static int clock_control_bl61x_on(const struct device *dev, clock_control_subsys_t sys) +{ + struct clock_control_bl61x_data *data = dev->data; + int ret = -EINVAL; + uint32_t key; + enum bl61x_clkid oldroot; + + key = irq_lock(); + + if ((enum bl61x_clkid)sys == bl61x_clkid_clk_crystal) { + if (data->crystal_enabled) { + ret = 0; + } else { + data->crystal_enabled = true; + ret = clock_control_bl61x_update_root(dev); + if (ret < 0) { + data->crystal_enabled = false; + } + } + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_wifipll) { + if (data->wifipll_enabled) { + ret = 0; + } else { + data->wifipll_enabled = true; + ret = clock_control_bl61x_update_root(dev); + if (ret < 0) { + data->wifipll_enabled = false; + } + } + } else if ((int)sys == BFLB_FORCE_ROOT_RC32M) { + if (data->root.source == bl61x_clkid_clk_rc32m) { + ret = 0; + } else { + /* Cannot fail to set root to rc32m */ + data->root.source = bl61x_clkid_clk_rc32m; + ret = clock_control_bl61x_update_root(dev); + } + } else if ((int)sys == BFLB_FORCE_ROOT_CRYSTAL) { + if (data->root.source == bl61x_clkid_clk_crystal) { + ret = 0; + } else { + oldroot = data->root.source; + data->root.source = bl61x_clkid_clk_crystal; + ret = clock_control_bl61x_update_root(dev); + if (ret < 0) { + data->root.source = oldroot; + } + } + } else if ((int)sys == BFLB_FORCE_ROOT_PLL) { + if (data->root.source == bl61x_clkid_clk_wifipll) { + ret = 0; + } else { + oldroot = data->root.source; + data->root.source = bl61x_clkid_clk_wifipll; + ret = clock_control_bl61x_update_root(dev); + if (ret < 0) { + data->root.source = oldroot; + } + } + } + + irq_unlock(key); + return ret; +} + +static int clock_control_bl61x_off(const struct device *dev, clock_control_subsys_t sys) +{ + struct clock_control_bl61x_data *data = dev->data; + int ret = -EINVAL; + uint32_t key; + + key = irq_lock(); + + if ((enum bl61x_clkid)sys == bl61x_clkid_clk_crystal) { + if (!data->crystal_enabled) { + ret = 0; + } else { + data->crystal_enabled = false; + ret = clock_control_bl61x_update_root(dev); + if (ret < 0) { + data->crystal_enabled = true; + } + } + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_wifipll) { + if (!data->wifipll_enabled) { + ret = 0; + } else { + data->wifipll_enabled = false; + ret = clock_control_bl61x_update_root(dev); + if (ret < 0) { + data->wifipll_enabled = true; + } + } + } + + irq_unlock(key); + return ret; +} + +static enum clock_control_status clock_control_bl61x_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + struct clock_control_bl61x_data *data = dev->data; + + if ((enum bl61x_clkid)sys == bl61x_clkid_clk_root) { + return CLOCK_CONTROL_STATUS_ON; + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_bclk) { + return CLOCK_CONTROL_STATUS_ON; + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_crystal) { + if (data->crystal_enabled) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_rc32m) { + return CLOCK_CONTROL_STATUS_ON; + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_wifipll) { + if (data->wifipll_enabled) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_aupll) { + if (data->aupll_enabled) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } + } + return -EINVAL; +} + +static int clock_control_bl61x_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + if ((enum bl61x_clkid)sys == bl61x_clkid_clk_root) { + *rate = clock_control_bl61x_get_hclk(dev); + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_bclk) { + *rate = clock_control_bl61x_get_bclk(dev); + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_crystal) { + *rate = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), clock_frequency); + } else if ((enum bl61x_clkid)sys == bl61x_clkid_clk_rc32m) { + *rate = BFLB_RC32M_FREQUENCY; + } else { + return -EINVAL; + } + return 0; +} + +static int clock_control_bl61x_init(const struct device *dev) +{ + int ret; + uint32_t key; + + key = irq_lock(); + + ret = clock_control_bl61x_update_root(dev); + if (ret < 0) { + irq_unlock(key); + return ret; + } + + clock_control_bl61x_peripheral_clock_init(); + + clock_bflb_settle(); + + clock_control_bl61x_update_flash_clk(dev); + + irq_unlock(key); + + return 0; +} + +static DEVICE_API(clock_control, clock_control_bl61x_api) = { + .on = clock_control_bl61x_on, + .off = clock_control_bl61x_off, + .get_rate = clock_control_bl61x_get_rate, + .get_status = clock_control_bl61x_get_status, +}; + +static const struct clock_control_bl61x_config clock_control_bl61x_config = { + .crystal_id = CRYSTAL_FREQ_TO_ID(DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal), + clock_frequency)), +}; + +static struct clock_control_bl61x_data clock_control_bl61x_data = { + .crystal_enabled = DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal)), + .wifipll_enabled = DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, wifipll_320)), + .aupll_enabled = DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, aupll_div1)), + + .root = { +#if CLK_SRC_IS(root, wifipll_320) + .pll_select = DT_CLOCKS_CELL(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), select) & 0xF, + .source = bl61x_clkid_clk_wifipll, +#elif CLK_SRC_IS(root, aupll_div1) + .pll_select = DT_CLOCKS_CELL(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), select) & 0xF, + .source = bl61x_clkid_clk_aupll, +#elif CLK_SRC_IS(root, crystal) + .source = bl61x_clkid_clk_crystal, +#else + .source = bl61x_clkid_clk_rc32m, +#endif + .divider = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), divider), + }, + + .wifipll = { +#if CLK_SRC_IS(wifipll_320, crystal) + .source = bl61x_clkid_clk_crystal, +#else + .source = bl61x_clkid_clk_rc32m, +#endif +#if CLK_SRC_IS(root, wifipll_320) + .overclock = DT_CLOCKS_CELL(DT_INST_CLOCKS_CTLR_BY_NAME(0, root), select) & 0x10, +#endif + }, + + .aupll = { +#if CLK_SRC_IS(aupll_div1, crystal) + .source = bl61x_clkid_clk_crystal, +#else + .source = bl61x_clkid_clk_rc32m, +#endif + }, + + .bclk = { + .divider = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, bclk), divider), + }, + + .flashclk = { +#if CLK_SRC_IS(flash, crystal) + .source = bl61x_clkid_clk_crystal, +#elif CLK_SRC_IS(flash, bclk) + .source = bl61x_clkid_clk_bclk, +#elif CLK_SRC_IS(flash, wifipll_320) + .source = bl61x_clkid_clk_wifipll, +#elif CLK_SRC_IS(flash, aupll_div1) + .source = bl61x_clkid_clk_aupll, +#else + .source = bl61x_clkid_clk_rc32m, +#endif + .bank1_read_delay = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, flash), read_delay), + .bank1_clock_invert = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, flash), clock_invert), + .bank1_rx_clock_invert = + DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, flash), rx_clock_invert), + .divider = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, flash), divider), + }, +}; + +BUILD_ASSERT(CLK_SRC_IS(aupll_div1, crystal) + || CLK_SRC_IS(wifipll_320, crystal) + || CLK_SRC_IS(root, crystal) + ? DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, crystal)) : 1, + "Crystal must be enabled to use it"); + +BUILD_ASSERT(CLK_SRC_IS(root, wifipll_320) + ? DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, wifipll_320)) : 1, + "Wifi PLL must be enabled to use it"); + +BUILD_ASSERT(CLK_SRC_IS(root, aupll_div1) + ? DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, aupll_div1)) : 1, + "Audio PLL must be enabled to use it"); + +BUILD_ASSERT(DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, rc32m)), + "RC32M is always on"); + +BUILD_ASSERT(!DT_NODE_HAS_STATUS_OKAY(DT_INST_CLOCKS_CTLR_BY_NAME(0, aupll_div1)), + "Audio PLL is unsupported"); + +BUILD_ASSERT(DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rc32m), + clock_frequency) == BFLB_RC32M_FREQUENCY, "RC32M must be 32M"); + +DEVICE_DT_INST_DEFINE(0, clock_control_bl61x_init, NULL, &clock_control_bl61x_data, + &clock_control_bl61x_config, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_bl61x_api); diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 0c42011ddf8b4..d8a1ccd02b571 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -63,4 +63,5 @@ add_subdirectory(renesas) if (CONFIG_PINCTRL_BFLB) zephyr_library_sources(pinctrl_bflb.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_BL60X pinctrl_bflb_bl60x_70x.c) + zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_BL61X pinctrl_bflb_bl61x.c) endif() diff --git a/drivers/pinctrl/pinctrl_bflb.c b/drivers/pinctrl/pinctrl_bflb.c index f41055c0794d5..397b289edeeb1 100644 --- a/drivers/pinctrl/pinctrl_bflb.c +++ b/drivers/pinctrl/pinctrl_bflb.c @@ -11,6 +11,8 @@ #if defined(CONFIG_SOC_SERIES_BL60X) #include +#elif defined(CONFIG_SOC_SERIES_BL61X) +#include #else #error "Unsupported Platform" #endif diff --git a/drivers/pinctrl/pinctrl_bflb_bl61x.c b/drivers/pinctrl/pinctrl_bflb_bl61x.c new file mode 100644 index 0000000000000..dc819622ea1cd --- /dev/null +++ b/drivers/pinctrl/pinctrl_bflb_bl61x.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#if defined(CONFIG_SOC_SERIES_BL61X) +#include +#else +#error "Unsupported Platform" +#endif + +void pinctrl_bflb_configure_uart(uint8_t pin, uint8_t func) +{ + uint32_t regval, regval2; + uint8_t sig, sig_pos; + + /* gpio pad check goes here */ + + sig = pin % 12; + + if (sig < 8) { + sig_pos = sig << 2; + + regval = sys_read32(GLB_BASE + GLB_UART_CFG1_OFFSET); + regval &= (~(0x0f << sig_pos)); + regval |= (func << sig_pos); + + for (uint8_t i = 0; i < 8; i++) { + /* reset other sigs which are the same as 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); + } + } + regval2 = sys_read32(GLB_BASE + GLB_UART_CFG2_OFFSET); + + for (uint8_t i = 8; i < 12; i++) { + /* reset other sigs which are the same as func */ + sig_pos = (i - 8) << 2; + if (((regval2 & (0x0f << sig_pos)) == (func << sig_pos)) + && (i != sig) && (func != 0x0f)) { + regval2 &= (~(0x0f << sig_pos)); + regval2 |= (0x0f << sig_pos); + } + } + sys_write32(regval, GLB_BASE + GLB_UART_CFG1_OFFSET); + sys_write32(regval2, GLB_BASE + GLB_UART_CFG2_OFFSET); + } else { + sig_pos = (sig - 8) << 2; + + regval = sys_read32(GLB_BASE + GLB_UART_CFG2_OFFSET); + regval &= (~(0x0f << sig_pos)); + regval |= (func << sig_pos); + + for (uint8_t i = 8; i < 12; i++) { + /* reset other sigs which are the same as func */ + sig_pos = (i - 8) << 2; + if (((regval & (0x0f << sig_pos)) == (func << sig_pos)) + && (i != sig) && (func != 0x0f)) { + regval &= (~(0x0f << sig_pos)); + regval |= (0x0f << sig_pos); + } + } + regval2 = sys_read32(GLB_BASE + GLB_UART_CFG1_OFFSET); + + for (uint8_t i = 0; i < 8; i++) { + /* reset other sigs which are the same as func */ + sig_pos = i << 2; + if (((regval2 & (0x0f << sig_pos)) == (func << sig_pos)) + && (i != sig) && (func != 0x0f)) { + regval2 &= (~(0x0f << sig_pos)); + regval2 |= (0x0f << sig_pos); + } + } + sys_write32(regval, GLB_BASE + GLB_UART_CFG2_OFFSET); + sys_write32(regval2, GLB_BASE + GLB_UART_CFG1_OFFSET); + } +} + +void pinctrl_bflb_init_pin(pinctrl_soc_pin_t pin) +{ + uint8_t drive; + uint8_t function; + uint16_t mode; + uint8_t real_pin; + uint32_t cfg = 0; + + 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); + + /* gpio pad check goes here */ + + /* disable RC32K muxing */ + if (real_pin == 16) { + *(volatile uint32_t *)(HBN_BASE + HBN_PAD_CTRL_0_OFFSET) + &= ~(1 << HBN_REG_EN_AON_CTRL_GPIO_POS); + } else if (real_pin == 17) { + *(volatile uint32_t *)(HBN_BASE + HBN_PAD_CTRL_0_OFFSET) + &= ~(1 << (HBN_REG_EN_AON_CTRL_GPIO_POS + 1)); + } + + /* mask interrupt */ + cfg = GLB_REG_GPIO_0_INT_MASK_MSK; + + if (mode == BFLB_PINMUX_MODE_analog) { + function = 10; + } else if (mode == BFLB_PINMUX_MODE_periph) { + cfg |= GLB_REG_GPIO_0_IE_MSK; + } else { + function = 11; + + if (mode == BFLB_PINMUX_MODE_input) { + cfg |= GLB_REG_GPIO_0_IE_MSK; + } + + if (mode == BFLB_PINMUX_MODE_output) { + cfg |= GLB_REG_GPIO_0_OE_MSK; + } + } + + uint8_t pull_up = BFLB_PINMUX_GET_PULL_UP(pin); + uint8_t pull_down = BFLB_PINMUX_GET_PULL_DOWN(pin); + + if (pull_up) { + cfg |= GLB_REG_GPIO_0_PU_MSK; + } else if (pull_down) { + cfg |= GLB_REG_GPIO_0_PD_MSK; + } else { + } + + if (BFLB_PINMUX_GET_SMT(pin)) { + cfg |= GLB_REG_GPIO_0_SMT_MSK; + } + + cfg |= (drive << GLB_REG_GPIO_0_DRV_POS); + cfg |= (function << GLB_REG_GPIO_0_FUNC_SEL_POS); + + /* output is controlled by _set and _clr and not value of _o*/ + cfg |= 0x1 << GLB_REG_GPIO_0_MODE_POS; + + sys_write32(cfg, GLB_BASE + GLB_GPIO_CFG0_OFFSET + (real_pin << 2)); +} diff --git a/drivers/syscon/syscon_bflb_efuse.c b/drivers/syscon/syscon_bflb_efuse.c index 747e47876d7cb..a0fa868b83d76 100644 --- a/drivers/syscon/syscon_bflb_efuse.c +++ b/drivers/syscon/syscon_bflb_efuse.c @@ -12,10 +12,10 @@ #include LOG_MODULE_REGISTER(efuse_bflb, CONFIG_SYSCON_LOG_LEVEL); -#include -#include -#include -#include +#include +#include +#include +#include #include struct efuse_bflb_data { diff --git a/dts/bindings/clock/bflb,bl61x-aupll.yaml b/dts/bindings/clock/bflb,bl61x-aupll.yaml new file mode 100644 index 0000000000000..e223900ce2d3d --- /dev/null +++ b/dts/bindings/clock/bflb,bl61x-aupll.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: The BL61x Audio PLL + +compatible: "bflb,bl61x-aupll" + +include: [base.yaml, clock-controller.yaml] + +properties: + clocks: + type: phandle-array + required: true + description: source + + "#clock-cells": + const: 1 + +clock-cells: + - select diff --git a/dts/bindings/clock/bflb,bl61x-clock-controller.yaml b/dts/bindings/clock/bflb,bl61x-clock-controller.yaml new file mode 100644 index 0000000000000..4c86cfb961520 --- /dev/null +++ b/dts/bindings/clock/bflb,bl61x-clock-controller.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: Bouffalolab BL61x Clock Controller + +compatible: "bflb,bl61x-clock-controller" + +include: [base.yaml, clock-controller.yaml] + +properties: + "#clock-cells": + const: 1 + +clock-cells: + - id diff --git a/dts/bindings/clock/bflb,bl61x-flash-clk.yaml b/dts/bindings/clock/bflb,bl61x-flash-clk.yaml new file mode 100644 index 0000000000000..637801f587444 --- /dev/null +++ b/dts/bindings/clock/bflb,bl61x-flash-clk.yaml @@ -0,0 +1,48 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: | + The BL61x Flash Clock + Source -> divider -> CLK + Only has settings for Bank 1 (boot flash) at the moment. + +compatible: "bflb,bl61x-flash-clk" + +include: [base.yaml, clock-controller.yaml] + +properties: + clocks: + type: phandle-array + required: true + description: Source clocks. + Using WIFIPLL results in WIFIPLL x 0.375 (120M). + When using RC32M main clock, use BCLK. + + divider: + type: int + default: 1 + description: Divide source clock by this 3-bits value (1 to 8). Typically 1. + + read-delay: + type: int + default: 0 + enum: + - 0 + - 1 + - 2 + - 3 + description: Flash Read delay. This is a flash controller setting. + This may be necessary to achieve flash clock higher than XCLK. + + clock-invert: + type: boolean + description: Invert Clock Signal. This is a flash controller setting. + This may be necessary to achieve flash clock higher than XCLK. + + rx-clock-invert: + type: boolean + description: Invert RX Clock Signal. This is a flash controller setting. + This may be necessary to achieve flash clock higher than XCLK. + + "#clock-cells": + const: 0 diff --git a/dts/bindings/clock/bflb,bl61x-root-clk.yaml b/dts/bindings/clock/bflb,bl61x-root-clk.yaml new file mode 100644 index 0000000000000..b858d4acaefad --- /dev/null +++ b/dts/bindings/clock/bflb,bl61x-root-clk.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: | + The BL61x Root Clock + Represents both FCLK and HCLK, which should be kept the same. + Source -> FCLK / divider -> HCLK / divider -> BCLK + +compatible: "bflb,bl61x-root-clk" + +include: [base.yaml, clock-controller.yaml] + +properties: + clocks: + type: phandle-array + required: true + description: source + + divider: + type: int + required: true + description: Divide source clock by this 8-bits value (FCLK divider). Typically 1. + + "#clock-cells": + const: 0 diff --git a/dts/bindings/clock/bflb,bl61x-wifipll.yaml b/dts/bindings/clock/bflb,bl61x-wifipll.yaml new file mode 100644 index 0000000000000..bef5f88e6a87c --- /dev/null +++ b/dts/bindings/clock/bflb,bl61x-wifipll.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# SPDX-License-Identifier: Apache-2.0 + +description: The BL61x WIFI PLL + +compatible: "bflb,bl61x-wifipll" + +include: [base.yaml, clock-controller.yaml] + +properties: + clocks: + type: phandle-array + required: true + description: source + + "#clock-cells": + const: 1 + +clock-cells: + - select diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index 29299d496eb17..c917e337099d6 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -772,6 +772,7 @@ xiphera Xiphera Ltd. xlnx Xilinx xnano Xnano xptek Shenzhen Xptek Technology Co., Ltd +xuantie Alibaba Xuantie xunlong Shenzhen Xunlong Software CO.,Limited xylon Xylon yamaha Yamaha Corporation diff --git a/dts/riscv/bflb/bl616.dtsi b/dts/riscv/bflb/bl616.dtsi new file mode 100644 index 0000000000000..b04a9d5fe6fd2 --- /dev/null +++ b/dts/riscv/bflb/bl616.dtsi @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/bflb/bl618.dtsi b/dts/riscv/bflb/bl618.dtsi new file mode 100644 index 0000000000000..47cfc3b899955 --- /dev/null +++ b/dts/riscv/bflb/bl618.dtsi @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/bflb/bl61x.dtsi b/dts/riscv/bflb/bl61x.dtsi new file mode 100644 index 0000000000000..5e4de9d544e95 --- /dev/null +++ b/dts/riscv/bflb/bl61x.dtsi @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + clocks { + clk_rc32m: clk-rc32m { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "okay"; + }; + + clk_crystal: clk-crystal { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "okay"; + }; + + clk_wifipll: clk-wifipll { + #clock-cells = <1>; + compatible = "bflb,bl61x-wifipll"; + clocks = <&clk_crystal>; + status = "okay"; + }; + + clk_aupll: clk-aupll { + #clock-cells = <1>; + compatible = "bflb,bl61x-aupll"; + clocks = <&clk_rc32m>; + status = "disabled"; + }; + + clk_root: clk-root { + #clock-cells = <0>; + compatible = "bflb,bl61x-root-clk"; + clocks = <&clk_wifipll BL61X_WIFIPLL_320MHz>; + divider = <1>; + status = "okay"; + }; + + clk_bclk: clk-bclk { + #clock-cells = <0>; + compatible = "bflb,bclk"; + divider = <4>; + status = "okay"; + }; + + clk_flash: clk-flash { + #clock-cells = <0>; + compatible = "bflb,bl61x-flash-clk"; + clocks = <&clk_bclk>; + divider = <2>; + status = "okay"; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = ; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "xuantie,e907", "riscv"; + reg = <0>; + riscv,isa = "rv32imafcp"; + hardware-exec-breakpoint-count = <4>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <1>; + clic: clic@e0800000 { + compatible = "nuclei,eclic"; + reg = <0xe0800000 0x10000>; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + }; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mtimer: timer@e000bff8 { + compatible = "riscv,machine-timer"; + reg = <0xE000BFF8 0x8 0xE0004000 0x8>; + reg-names = "mtime", "mtimecmp"; + + interrupts-extended = <&clic 7 1>; + }; + + pinctrl: pin-controller@20000000 { + compatible = "bflb,pinctrl"; + reg = <0x20000000 0x1000>; + ranges = <0x20000000 0x20000000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + + gpio0: gpio@20000000 { + compatible = "bflb,gpio"; + reg = <0x20000000 0x1000>; + #gpio-cells = <2>; + #bflb,pin-cells = <2>; + status = "disabled"; + + gpio-controller; + interrupts = <60 1>; + interrupt-parent = <&clic>; + }; + }; + + clocks: clock-controller@20000000 { + compatible = "bflb,bl61x-clock-controller", "bflb,clock-controller"; + reg = <0x20000000 DT_SIZE_K(4)>; + #clock-cells = <1>; + status = "okay"; + clocks = <&clk_rc32m>, <&clk_crystal>, + <&clk_wifipll BL61X_WIFIPLL_320MHz>, + <&clk_wifipll BL61X_WIFIPLL_240MHz>, + <&clk_wifipll BL61X_WIFIPLL_OC_480MHz>, + <&clk_wifipll BL61X_WIFIPLL_OC_360MHz>, + <&clk_aupll BL61X_AUPLL_DIV1>, <&clk_aupll BL61X_AUPLL_DIV2>, + <&clk_root>, <&clk_bclk>, <&clk_flash>; + clock-names = "rc32m", "crystal", + "wifipll_320", + "wifipll_240", + "wifipll_480", + "wifipll_360", + "aupll_div1", "aupll_div2", + "root", "bclk", "flash"; + }; + + uart0: uart@2000a000 { + compatible = "bflb,uart"; + reg = <0x2000a000 0x100>; + interrupts = <44 1>; + interrupt-parent = <&clic>; + status = "disabled"; + }; + + uart1: uart@4000a100 { + compatible = "bflb,uart"; + reg = <0x4000a100 0x100>; + interrupts = <45 1>; + interrupt-parent = <&clic>; + status = "disabled"; + }; + + flashctrl: flash-controller@2000b000 { + compatible = "bflb,flash-controller"; + reg = <0x2000b000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + interrupts = <29 1>; + interrupt-parent = <&clic>; + }; + + retram: memory@20010000 { + compatible = "mmio-sram"; + reg = <0x20010000 DT_SIZE_K(4)>; + }; + + efuse: efuse@20056000 { + compatible = "bflb,efuse"; + reg = <0x20056000 0x1000>; + status = "okay"; + size = <512>; + }; + + sram0: memory@62fc0000 { + compatible = "mmio-sram"; + reg = <0x62FC0000 DT_SIZE_K(320)>; + }; + + sram1: memory@63010000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x63010000 DT_SIZE_K(160)>; + zephyr,memory-region = "ITCM"; + }; + }; +}; diff --git a/include/zephyr/dt-bindings/clock/bflb_bl61x_clock.h b/include/zephyr/dt-bindings/clock/bflb_bl61x_clock.h new file mode 100644 index 0000000000000..cb6ac88f1cfd4 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/bflb_bl61x_clock.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_BFLB_BL61X_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_BFLB_BL61X_CLOCK_H_ + +#include "bflb_clock_common.h" + +#define BL61X_CLKID_CLK_ROOT BFLB_CLKID_CLK_ROOT +#define BL61X_CLKID_CLK_RC32M BFLB_CLKID_CLK_RC32M +#define BL61X_CLKID_CLK_CRYSTAL BFLB_CLKID_CLK_CRYSTAL +#define BL61X_CLKID_CLK_BCLK BFLB_CLKID_CLK_BCLK +#define BL61X_CLKID_CLK_WIFIPLL 4 +#define BL61X_CLKID_CLK_AUPLL 5 + +#define BL61X_AUPLL_DIV2 0 +#define BL61X_AUPLL_DIV1 1 +#define BL61X_WIFIPLL_240MHz 2 +#define BL61X_WIFIPLL_320MHz 3 + +/* Overclocked + * Overclock PLL to 480MHz for div ID 1 and 360MHz for div ID 2 + * BCLK divider MUST be set so BCLK is 80MHz or slower + * Breaks most complex peripherals (Wifi) + */ +#define BL61X_WIFIPLL_OC_360MHz (2 | 0x10) +#define BL61X_WIFIPLL_OC_480MHz (3 | 0x10) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_BFLB_BL61X_CLOCK_H_ */ diff --git a/soc/bflb/bl61x/CMakeLists.txt b/soc/bflb/bl61x/CMakeLists.txt new file mode 100644 index 0000000000000..9760222051f90 --- /dev/null +++ b/soc/bflb/bl61x/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") + +zephyr_code_relocate_ifdef(CONFIG_UART_BFLB LIBRARY drivers__serial LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_RISCV_MACHINE_TIMER LIBRARY drivers__timer LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_PINCTRL_BFLB LIBRARY drivers__pinctrl LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_SYSCON_BFLB_EFUSE LIBRARY drivers__syscon LOCATION ITCM NOKEEP) +zephyr_code_relocate_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL61X + LIBRARY drivers__clock_control LOCATION ITCM NOKEEP) diff --git a/soc/bflb/bl61x/Kconfig b/soc/bflb/bl61x/Kconfig new file mode 100644 index 0000000000000..6030a27709386 --- /dev/null +++ b/soc/bflb/bl61x/Kconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL61X + select CLOCK_CONTROL + select CODE_DATA_RELOCATION + select CPU_HAS_FPU + select FLOAT_HARD + select FPU + select GEN_IRQ_VECTOR_TABLE + select INCLUDE_RESET_VECTOR + select RISCV + select RISCV_HAS_CLIC + select RISCV_MACHINE_TIMER + select RISCV_PRIVILEGED + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_F + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_VECTORED_MODE + select SOC_EARLY_INIT_HOOK + select SYSCON + select XIP diff --git a/soc/bflb/bl61x/Kconfig.defconfig b/soc/bflb/bl61x/Kconfig.defconfig new file mode 100644 index 0000000000000..6b75e25583545 --- /dev/null +++ b/soc/bflb/bl61x/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_BL61X + +config SYS_CLOCK_TICKS_PER_SEC + default 5000 + +config NUM_IRQS + default 96 + +config ARCH_SW_ISR_TABLE_ALIGN + default 64 + +config RISCV_MCAUSE_EXCEPTION_MASK + default 0xFFF + +endif # SOC_SERIES_BL61X diff --git a/soc/bflb/bl61x/Kconfig.soc b/soc/bflb/bl61x/Kconfig.soc new file mode 100644 index 0000000000000..db8fb08ba0ab8 --- /dev/null +++ b/soc/bflb/bl61x/Kconfig.soc @@ -0,0 +1,39 @@ +# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL61X + bool + select SOC_FAMILY_BFLB + help + Enable support for BouffaloLab BL6xx MCU series + +config SOC_SERIES + default "bl61x" if SOC_SERIES_BL61X + +config SOC_BL616C50Q2I + bool + select SOC_SERIES_BL61X + +config SOC_BL616S50Q2I + bool + select SOC_SERIES_BL61X + +config SOC_BL618M05Q2I + bool + select SOC_SERIES_BL61X + +config SOC_BL618M50Q2I + bool + select SOC_SERIES_BL61X + +config SOC_BL618M65Q2I + bool + select SOC_SERIES_BL61X + +config SOC + default "bl616c50q2i" if SOC_BL616C50Q2I + default "bl616s50q2i" if SOC_BL616S50Q2I + default "bl618m05q2i" if SOC_BL618M05Q2I + default "bl618m50q2i" if SOC_BL618M50Q2I + default "bl618m65q2i" if SOC_BL618M65Q2I diff --git a/soc/bflb/bl61x/soc.c b/soc/bflb/bl61x/soc.c new file mode 100644 index 0000000000000..69d5274a1b8e6 --- /dev/null +++ b/soc/bflb/bl61x/soc.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Bouffalo Lab RISC-V MCU series initialization code + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* brown out detection */ +void system_BOD_init(void) +{ + uint32_t tmpVal = 0; + + /* disable BOD interrupt */ + tmpVal = sys_read32(HBN_BASE + HBN_IRQ_MODE_OFFSET); + tmpVal &= ~HBN_IRQ_BOR_EN_MSK; + sys_write32(tmpVal, HBN_BASE + HBN_IRQ_MODE_OFFSET); + + tmpVal = sys_read32(HBN_BASE + HBN_BOR_CFG_OFFSET); + /* when brownout threshold, restart*/ + tmpVal |= HBN_BOD_SEL_MSK; + /* set BOD threshold: + * 0:2.05v,1:2.10v,2:2.15v....7:2.4v + */ + tmpVal &= ~HBN_BOD_VTH_MSK; + tmpVal |= (7 << HBN_BOD_VTH_POS); + /* enable BOD */ + tmpVal |= HBN_PU_BOD_MSK; + sys_write32(tmpVal, HBN_BASE + HBN_BOR_CFG_OFFSET); +} + +static void clean_dcache(void) +{ + __asm__ volatile ( + "fence\n" + /* th.dcache.call*/ + ".insn 0x10000B\n" + "fence\n" + ); +} + +static void clean_icache(void) +{ + __asm__ volatile ( + "fence\n" + "fence.i\n" + /* th.icache.iall */ + ".insn 0x100000B\n" + "fence\n" + "fence.i\n" + ); +} + +static void enable_icache(void) +{ + uint32_t tmpVal = 0; + + __asm__ volatile ( + "fence\n" + "fence.i\n" + /* th.icache.iall */ + ".insn 0x100000B\n" + ); + __asm__ volatile( + "csrr %0, 0x7C1" + : "=r"(tmpVal)); + tmpVal |= (1 << 0); + __asm__ volatile( + "csrw 0x7C1, %0" + : + : "r"(tmpVal)); + __asm__ volatile ( + "fence\n" + "fence.i\n" + ); +} + +static void enable_dcache(void) +{ + uint32_t tmpVal = 0; + + __asm__ volatile ( + "fence\n" + "fence.i\n" + /* th.dcache.iall */ + ".insn 0x20000B\n" + ); + __asm__ volatile( + "csrr %0, 0x7C1" + : "=r"(tmpVal)); + tmpVal |= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4); + __asm__ volatile( + "csrw 0x7C1, %0" + : + : "r"(tmpVal)); + __asm__ volatile ( + "fence\n" + "fence.i\n" + ); +} + +static void enable_branchpred(bool yes) +{ + uint32_t tmpVal = 0; + + __asm__ volatile ( + "fence\n" + "fence.i\n" + ); + __asm__ volatile( + "csrr %0, 0x7C1" + : "=r"(tmpVal)); + if (yes) { + tmpVal |= (1 << 5) | (1 << 12); + } else { + tmpVal &= ~((1 << 5) | (1 << 12)); + } + __asm__ volatile( + "csrw 0x7C1, %0" + : + : "r"(tmpVal)); + __asm__ volatile ( + "fence\n" + "fence.i\n" + ); +} + +static void enable_thead_isa_ext(void) +{ + uint32_t tmpVal = 0; + + __asm__ volatile( + "csrr %0, 0x7C0" + : "=r"(tmpVal)); + tmpVal |= (1 << 22); + __asm__ volatile( + "csrw 0x7C0, %0" + : + : "r"(tmpVal)); +} + +static void set_thead_enforce_aligned(bool enable) +{ + uint32_t tmpVal = 0; + + __asm__ volatile( + "csrr %0, 0x7C0" + : "=r"(tmpVal)); + if (enable) { + tmpVal &= ~(1 << 15); + } else { + tmpVal |= (1 << 15); + } + __asm__ volatile( + "csrw 0x7C0, %0" + : + : "r"(tmpVal)); +} + +static void disable_interrupt_autostacking(void) +{ + uint32_t tmpVal = 0; + + __asm__ volatile( + "csrr %0, 0x7E1" + : "=r"(tmpVal)); + tmpVal &= ~(0x3 << 16); + __asm__ volatile( + "csrw 0x7E1, %0" + : + : "r"(tmpVal)); +} + + +void soc_early_init_hook(void) +{ + uint32_t key; + uint32_t tmp; + + key = irq_lock(); + + + /* turn off USB power */ + sys_write32((1 << 5), PDS_BASE + PDS_USB_CTL_OFFSET); + sys_write32(0, PDS_BASE + PDS_USB_PHY_CTRL_OFFSET); + + enable_thead_isa_ext(); + set_thead_enforce_aligned(false); + enable_dcache(); + /* branch prediction can cause major slowdowns (250ms -> 2 seconds) + * in some applications + */ + enable_branchpred(true); + enable_icache(); + disable_interrupt_autostacking(); + clean_dcache(); + clean_icache(); + + /* reset uart signals */ + sys_write32(0xffffffffU, GLB_BASE + GLB_UART_CFG1_OFFSET); + sys_write32(0x0000ffffU, GLB_BASE + GLB_UART_CFG2_OFFSET); + + /* reset wrongful AON control set by Bootrom on BL618 */ + tmp = sys_read32(HBN_BASE + HBN_PAD_CTRL_0_OFFSET); + tmp &= ~HBN_REG_EN_AON_CTRL_GPIO_MSK; + sys_write32(tmp, HBN_BASE + HBN_PAD_CTRL_0_OFFSET); + + /* TODO: 'em' config for ble goes here */ + + system_BOD_init(); + + irq_unlock(key); +} diff --git a/soc/bflb/bl61x/soc.h b/soc/bflb/bl61x/soc.h new file mode 100644 index 0000000000000..19cb5f75ea9d7 --- /dev/null +++ b/soc/bflb/bl61x/soc.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021-2025 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Board configuration macros + * + * This header file is used to specify and describe board-level aspects + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +#include + +#ifndef _ASMLANGUAGE + +/* Add include for DTS generated information */ +#include + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC__H_ */ diff --git a/soc/bflb/soc.yml b/soc/bflb/soc.yml index 8b3c61e0f3cdb..1be1f88d5c738 100644 --- a/soc/bflb/soc.yml +++ b/soc/bflb/soc.yml @@ -10,4 +10,11 @@ family: - name: bl602l10q2h - name: bl602l20q2h - name: bl604e20q2i + - name: bl61x + socs: + - name: bl616c50q2i + - name: bl616s50q2i + - name: bl618m05q2i + - name: bl618m50q2i + - name: bl618m65q2i vendor: bflb