diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c0c4fe5c556c..bf084f79d502 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: diff --git a/boards/bouffalolab/bl60x/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk b/boards/bouffalolab/bl60x/bl604e_iot_dvk/Kconfig.bl604e_iot_dvk new file mode 100644 index 000000000000..ae82bd6f2d8c --- /dev/null +++ b/boards/bouffalolab/bl60x/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/bl60x/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk-pinctrl.dtsi new file mode 100644 index 000000000000..f773fcae87bb --- /dev/null +++ b/boards/bouffalolab/bl60x/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/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.dts b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.dts new file mode 100644 index 000000000000..8648c9363a6b --- /dev/null +++ b/boards/bouffalolab/bl60x/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/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml new file mode 100644 index 000000000000..420f3736ad4f --- /dev/null +++ b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml @@ -0,0 +1,20 @@ +# 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: + - gpio + - pinctrl + - uart +vendor: bflb diff --git a/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk_defconfig b/boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk_defconfig new file mode 100644 index 000000000000..d736e43f5d50 --- /dev/null +++ b/boards/bouffalolab/bl60x/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/bl60x/bl604e_iot_dvk/board.cmake b/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake new file mode 100644 index 000000000000..bdf0d1a10833 --- /dev/null +++ b/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.cmake @@ -0,0 +1,25 @@ +# 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(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/board.yml b/boards/bouffalolab/bl60x/bl604e_iot_dvk/board.yml new file mode 100644 index 000000000000..843d38b0e8a2 --- /dev/null +++ b/boards/bouffalolab/bl60x/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/bl60x/bl604e_iot_dvk/doc/img/bl_604e.jpg b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/img/bl_604e.jpg new file mode 100644 index 000000000000..05700b35504e Binary files /dev/null and b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/img/bl_604e.jpg differ diff --git a/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst new file mode 100644 index 000000000000..514b7d9f269d --- /dev/null +++ b/boards/bouffalolab/bl60x/bl604e_iot_dvk/doc/index.rst @@ -0,0 +1,134 @@ +.. zephyr:board:: bl604e_iot_dvk + +Overview +******** + +BL602/BL604 is a Wi-Fi+BLE chipset introduced by Bouffalo Lab, which is used +for low power consumption and high performance application development. The +wireless subsystem includes 2.4G radio, Wi-Fi 802.11b/g/n and BLE 5.0 +baseband/MAC design. The microcontroller subsystem includes a 32-bit RISC CPU +with low power consumption, cache and memory. The power management unit +controls the low power consumption mode. In addition, it also supports +various security features. The external interfaces include SDIO, SPI, UART, +I2C, IR remote, PWM, ADC, DAC, PIR and GPIO. + +The BL602 Development Board features a SiFive E24 32 bit RISC-V CPU with FPU, +it supports High Frequency clock up to 192Mhz, have 128k ROM, 276kB RAM, +2.4 GHz WIFI 1T1R mode, support 20 MHz, data rate up to 72.2 Mbps, BLE 5.0 +with 2MB phy. It is a secure MCU which supports Secure boot, ECC-256 signed +image, QSPI/SPI Flash On-The-Fly AES Decryption and PKA (Public Key +Accelerator). + +Hardware +******** + +For more information about the Bouffalo Lab BL-60x MCU: + +- `Bouffalo Lab BL60x MCU Website`_ +- `Bouffalo Lab BL60x MCU Datasheet`_ +- `Bouffalo Lab Development Zone`_ +- `The RISC-V BL602 Book`_ + +Supported Features +================== + +The board configuration supports the following hardware features: + ++-----------+------------+-----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=======================+ +| MTIMER | on-chip | RISC-V Machine Timer | ++-----------+------------+-----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-----------------------+ +| PINCTRL | on-chip | pin muxing | ++-----------+------------+-----------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-----------------------+ + + +The default configurations can be found in the Kconfig +:zephyr_file:`boards/bouffalolab/bl60x/bl604e_iot_dvk/bl604e_iot_dvk_defconfig`. + +System Clock +============ + +The BL604E Development Board is configured to run at max speed (192MHz). + +Serial Port +=========== + +The ``bl604e_iot_dvk`` 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: bl604e_iot_dvk + :goals: build + :compact: + +#. To flash an image using bflb_mcu_tool runner: + + #. Press BOOT button + + #. Press and release RST button + + #. Release BOOT button + + .. code-block:: console + + west flash + +#. Run your favorite terminal program to listen for output. Under Linux the + terminal should be :code:`/dev/ttyACM0`. For example: + + .. code-block:: console + + $ minicom -D /dev/ttyACM0 -o + + 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 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. + + +.. _Bouffalo Lab BL60x MCU Website: + https://en.bouffalolab.com/product/?type=detail&id=6 + +.. _Bouffalo Lab BL60x MCU Datasheet: + https://github.com/bouffalolab/bl_docs/tree/main/BL602_DS/en + +.. _Bouffalo Lab Development Zone: + https://dev.bouffalolab.com/home?id=guest + +.. _The RISC-V BL602 Book: + https://lupyuen.github.io/articles/book + +.. _Flashing Firmware to BL602: + https://lupyuen.github.io/articles/book#flashing-firmware-to-bl602 diff --git a/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/bl6.cfg b/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/bl6.cfg new file mode 100644 index 000000000000..10538b208bcb --- /dev/null +++ b/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/bl6.cfg @@ -0,0 +1,79 @@ +# Copyright (c) 2022-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME riscv +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +if { [info exists WORKAREAADDR] } { + set _WORKAREAADDR $WORKAREAADDR +} else { + set _WORKAREAADDR 0x22020000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x20000c05 +} + +transport select jtag +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME + +$_TARGETNAME.0 configure -work-area-phys $_WORKAREAADDR -work-area-size $_WORKAREASIZE -work-area-backup 1 + +echo "Ready for Remote Connections" + +$_TARGETNAME.0 configure -event reset-assert-pre { + echo "reset-assert-pre" + adapter speed 100 +} + +$_TARGETNAME.0 configure -event reset-deassert-post { + echo "reset-deassert-post" + + adapter speed 100 + + reg mstatus 0x7800 + reg mie 0x0 +# reg pc 0x23000000 +} + +$_TARGETNAME.0 configure -event reset-init { + echo "reset-init" + + adapter speed 3000 +} + +$_TARGETNAME.0 configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME.0 configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +gdb_memory_map enable +gdb_flash_program enable + +# 'progbuf', 'sysbus' or 'abstract' +riscv set_mem_access sysbus +riscv set_command_timeout_sec 1 + +init +reset init diff --git a/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/openocd.cfg b/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/openocd.cfg new file mode 100644 index 000000000000..ffd60cfb196c --- /dev/null +++ b/boards/bouffalolab/bl60x/bl604e_iot_dvk/support/openocd.cfg @@ -0,0 +1,19 @@ +# OpenOCD Script for PineCone connected via Sipeed JTAG Debugger (FTDI FT2232D) +# Ref: bl_iot_sdk/tools/debug/if_bflb_link.cfg +# source [find interface/if_bflb_link.cfg] + +# Uncomment to enable debug messages +# debug_level 4 + +# BouffaloLab USB-JTAG/TTL adapter +# Or Sipeed JTAG Debugger based on FTDI FT2232D + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +# Sipeed JTAG Debugger uses FTDI Channel 0, not 1 +ftdi channel 0 +# ftdi_channel 1 + +ftdi layout_init 0x00f8 0x00fb +adapter speed 4000 diff --git a/boards/bouffalolab/index.rst b/boards/bouffalolab/index.rst new file mode 100644 index 000000000000..f0380b6b45c7 --- /dev/null +++ b/boards/bouffalolab/index.rst @@ -0,0 +1,10 @@ +.. _boards-bouffalolab: + +Bouffalo Lab Intelligent Technology (Nanjing) Co., Ltd. +####################################################### + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/boards/common/bflb_mcu_tool.board.cmake b/boards/common/bflb_mcu_tool.board.cmake new file mode 100644 index 000000000000..73862b0f5e19 --- /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/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index dcc4b96a54fa..d7e121669c1b 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 ba1ed8a3f64b..1f1d04a4114e 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 000000000000..c3cf15d66f6f --- /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 000000000000..152f51e5ee80 --- /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/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index d2834504eb2e..930e48956517 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 d8621e7ad9e1..844ec3c98ff9 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 000000000000..b98ad37915c0 --- /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 000000000000..d4593289ec11 --- /dev/null +++ b/drivers/pinctrl/pinctrl_bflb.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2021-2024 Gerson Fernando Budke + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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) +{ + uint8_t i; + + ARG_UNUSED(reg); + + 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])); + } + + /* gpio init*/ + pinctrl_bflb_init_pin(pins[i]); + } + + return 0; +} + +/* clang-format on */ diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index c3b1f8acdd91..28b00352e112 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 013f0343bd77..2e1e802bb4cf 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 000000000000..6383a60884c8 --- /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 SERIAL_SUPPORT_INTERRUPT + 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 000000000000..2fc44afdf0cc --- /dev/null +++ b/drivers/serial/uart_bflb.c @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) + * + * 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 +#include + +#include +#include +#include +#include +#include + +/* clang-format off */ + +struct bflb_config { + 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 */ +}; + +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 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; + + if (enable) { + enable = 1; + } + + 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 uint32_t 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); + } +} + +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 uint32_t uart_bflb_get_clock(void) +{ + 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)); + + } + } else { + /* UART PLL 160 */ + return (MHZ(160) / (uart_divider + 1)); + } + return 0; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +static int uart_bflb_err_check(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t status = 0; + uint32_t tmp = 0; + int errors = 0; + + 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 & UART_UTX_FER_INT) { + errors |= UART_ERROR_OVERRUN; + } + + if (status & UART_URX_PCE_INT) { + tmp |= UART_CR_URX_PCE_CLR; + + errors |= UART_ERROR_PARITY; + } + + sys_write32(tmp, cfg->base_reg + UART_INT_CLEAR_OFFSET); + + return errors; +} + +int uart_bflb_irq_tx_ready(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + tmp = sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET); + return (tmp & UART_TX_FIFO_CNT_MASK) > 0; +} + +int uart_bflb_irq_rx_ready(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + tmp = sys_read32(cfg->base_reg + UART_FIFO_CONFIG_1_OFFSET); + return (tmp & UART_RX_FIFO_CNT_MASK) > 0; +} + +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); + } + + return num_tx; +} + +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; + + 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; +} + +void uart_bflb_irq_tx_enable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + 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_bflb_irq_tx_disable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 0; + + 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_bflb_irq_tx_complete(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + 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_bflb_irq_rx_enable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 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_bflb_irq_rx_disable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 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_bflb_irq_err_enable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 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); +} + +void uart_bflb_irq_err_disable(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = 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_bflb_irq_is_pending(const struct device *dev) +{ + const struct bflb_config *const cfg = dev->config; + uint32_t tmp = sys_read32(cfg->base_reg + UART_INT_STS_OFFSET); + uint32_t maskVal = sys_read32(cfg->base_reg + UART_INT_MASK_OFFSET); + + /* only first 8 bits are not reserved */ + return (((tmp & ~maskVal) & 0xFF) != 0 ? 1 : 0); +} + +int uart_bflb_irq_update(const struct device *dev) +{ + ARG_UNUSED(dev); + + return 1; +} + +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; + + data->user_cb = cb; + data->user_data = user_data; +} + +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_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->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->pincfg, PINCTRL_STATE_SLEEP)) { + return -ENOTSUP; + } + + 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; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ + +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_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(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(instance), \ + DT_INST_IRQ(instance, priority), \ + uart_bflb_isr, \ + DEVICE_DT_INST_GET(instance), \ + 0); \ + irq_enable(DT_INST_IRQN(instance)); \ + } +#else /* CONFIG_UART_INTERRUPT_DRIVEN */ +#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 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) \ + \ + static struct bflb_data uart##instance##_bflb_data; \ + \ + 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(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) + +/* clang-format on */ diff --git a/drivers/timer/Kconfig.riscv_machine b/drivers/timer/Kconfig.riscv_machine index efbd4d322f73..19167ebe6d74 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 36e29c6aadb3..244405e40189 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/gpio/bflb,bl-gpio.yaml b/dts/bindings/gpio/bflb,bl-gpio.yaml new file mode 100644 index 000000000000..3e5ebcc6b2ed --- /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/interrupt-controller/sifive,clic.yaml b/dts/bindings/interrupt-controller/sifive,clic.yaml new file mode 100644 index 000000000000..dbc31e8ba100 --- /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 diff --git a/dts/bindings/pinctrl/bflb,bl-pinctrl.yaml b/dts/bindings/pinctrl/bflb,bl-pinctrl.yaml new file mode 100644 index 000000000000..d297065bc57f --- /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/bindings/serial/bflb,bl-uart.yaml b/dts/bindings/serial/bflb,bl-uart.yaml new file mode 100644 index 000000000000..dc248673127c --- /dev/null +++ b/dts/bindings/serial/bflb,bl-uart.yaml @@ -0,0 +1,15 @@ +# 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 diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index ee115b920f6f..2f3a79c9247c 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 diff --git a/dts/riscv/bouffalolab/bl602.dtsi b/dts/riscv/bouffalolab/bl602.dtsi new file mode 100644 index 000000000000..7899a0948c24 --- /dev/null +++ b/dts/riscv/bouffalolab/bl602.dtsi @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/bouffalolab/bl604e.dtsi b/dts/riscv/bouffalolab/bl604e.dtsi new file mode 100644 index 000000000000..cfe3c6ab2cc7 --- /dev/null +++ b/dts/riscv/bouffalolab/bl604e.dtsi @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2022-2024 ATL Electronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/dts/riscv/bouffalolab/bl60x.dtsi b/dts/riscv/bouffalolab/bl60x.dtsi new file mode 100644 index 000000000000..7af0bd223262 --- /dev/null +++ b/dts/riscv/bouffalolab/bl60x.dtsi @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#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 { + #address-cells = <0>; + #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"; + reg = <0x42020000 DT_SIZE_K(64)>; + }; + sram1: memory@42030000 { + compatible = "mmio-sram"; + reg = <0x42030000 DT_SIZE_K(112)>; + }; + + clic: clic@2000000 { + compatible = "sifive,clic"; + reg = <0x2000000 0x10000>; + reg-names = "control"; + + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + + interrupts-extended = <&ictrl 3 &ictrl 7 &ictrl 11 &ictrl 12>; + interrupt-names = "msip", /* Machine Software Interrupt */ + "mtip", /* Machine Timer interrupt */ + "meip", /* Machine External Interrupt */ + "csip"; /* CLIC Software Interrupt */ + }; + + pinctrl: pin-controller@40000000 { + compatible = "bflb,bl-pinctrl"; + reg = <0x40000000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0x1000>; + status = "okay"; + + gpio: gpio@40000000 { + compatible = "bflb,bl-gpio"; + reg = <0x40000000 0x1000>; + interrupts = <1 0>; + interrupt-parent = <&clic>; + gpio-controller; + #gpio-cells = <2>; + #bflb,pin-cells = <2>; + status = "disabled"; + }; + }; + + spi0: spi@4000a200 { + compatible = "bflb,bl-spi"; + reg = <0x4000a200 0x100>; + interrupts = <43 0>; + interrupt-parent = <&clic>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + spi1: spi@4000b000 { + compatible = "bflb,bl-qspi"; + reg = <0x4000b000 0x1000>; + interrupts = <39 0>; + interrupt-parent = <&clic>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: uart@4000a000 { + compatible = "bflb,bl-uart"; + reg = <0x4000a000 0x100>; + interrupts = <45 0>; + interrupt-parent = <&clic>; + status = "disabled"; + }; + uart1: uart@4000a100 { + compatible = "bflb,bl-uart"; + reg = <0x4000a100 0x100>; + interrupts = <46 0>; + interrupt-parent = <&clic>; + status = "disabled"; + }; + }; +}; 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 000000000000..e3aa44e0f9ba --- /dev/null +++ b/include/zephyr/drivers/pinctrl/pinctrl_soc_bflb_common.h @@ -0,0 +1,83 @@ +/* + * 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 +#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/Kconfig b/modules/Kconfig index a8cf861a6809..5fc054efdb89 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" @@ -66,6 +67,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/Kconfig.bouffalolab b/modules/Kconfig.bouffalolab new file mode 100644 index 000000000000..a6870be41085 --- /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 new file mode 100644 index 000000000000..4661a292f4bf --- /dev/null +++ b/modules/hal_bouffalolab/CMakeLists.txt @@ -0,0 +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) + +if (CONFIG_SOC_SERIES_BL60X) + zephyr_compile_definitions(BL602) +endif() + +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 new file mode 100644 index 000000000000..fee984ac1588 --- /dev/null +++ b/modules/hal_bouffalolab/Kconfig @@ -0,0 +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 diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index 3ed333c24c28..881c06efa092 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', 'bossac', 'canopen_program', 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 000000000000..534af9f2abd3 --- /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 3fb08b68a9e1..7b6126d3d3cb 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', 'bossac', 'canopen', diff --git a/soc/bouffalolab/CMakeLists.txt b/soc/bouffalolab/CMakeLists.txt new file mode 100644 index 000000000000..613bfe0e3a47 --- /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 000000000000..0420e03a79ac --- /dev/null +++ b/soc/bouffalolab/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +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 000000000000..10203e4bd368 --- /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 000000000000..3fc2a062c1cd --- /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/bl60x/CMakeLists.txt b/soc/bouffalolab/bl60x/CMakeLists.txt new file mode 100644 index 000000000000..91930a78450d --- /dev/null +++ b/soc/bouffalolab/bl60x/CMakeLists.txt @@ -0,0 +1,14 @@ +# 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) + +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) +zephyr_code_relocate_ifdef(CONFIG_UART_BFLB LIBRARY drivers__serial LOCATION ITCM) diff --git a/soc/bouffalolab/bl60x/Kconfig b/soc/bouffalolab/bl60x/Kconfig new file mode 100644 index 000000000000..591800a095d5 --- /dev/null +++ b/soc/bouffalolab/bl60x/Kconfig @@ -0,0 +1,26 @@ +# Copyright (c) 2021-2024 ATL Electronics +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL60X + select RISCV + select RISCV_MACHINE_TIMER + select RISCV_PRIVILEGED + select RISCV_HAS_CLIC + select RISCV_VECTORED_MODE + select ATOMIC_OPERATIONS_C + select CODE_DATA_RELOCATION + select CPU_HAS_FPU + select GEN_IRQ_VECTOR_TABLE + 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_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 000000000000..db2799d32cc9 --- /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/bl60x/Kconfig.soc b/soc/bouffalolab/bl60x/Kconfig.soc new file mode 100644 index 000000000000..c8839e612e04 --- /dev/null +++ b/soc/bouffalolab/bl60x/Kconfig.soc @@ -0,0 +1,50 @@ +# Copyright (c) 2021-2024 ATL Electronics +# Copyright (c) 2024 MASSDRIVER EI (massdriver.space) +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_BL60X + bool + select SOC_FAMILY_BFLB + help + Enable support for BouffaloLab BL6xx MCU series + +config SOC_SERIES + default "bl60x" if SOC_SERIES_BL60X + +config SOC_BL602C00Q2I + bool + select SOC_SERIES_BL60X + +config SOC_BL602C20Q2I + bool + select SOC_SERIES_BL60X + +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_BL60X + +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/bl60x/soc.c b/soc/bouffalolab/bl60x/soc.c new file mode 100644 index 000000000000..1e3620f3ef5c --- /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/bl60x/soc.h b/soc/bouffalolab/bl60x/soc.h new file mode 100644 index 000000000000..80ceb550d7f7 --- /dev/null +++ b/soc/bouffalolab/bl60x/soc.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021-2024 ATL Electronics + * Copyright (c) 2024 MASSDRIVER EI (massdriver.space) + * + * 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 + +/* 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_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 */ + +#endif /* _SOC__H_ */ diff --git a/soc/bouffalolab/common/CMakeLists.txt b/soc/bouffalolab/common/CMakeLists.txt new file mode 100644 index 000000000000..d7a8e877baaf --- /dev/null +++ b/soc/bouffalolab/common/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2021-2024 ATL Electronics +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_sources_ifdef(CONFIG_RISCV_PRIVILEGED + soc_common_irq_privileged.c + ) diff --git a/soc/bouffalolab/common/clic.h b/soc/bouffalolab/common/clic.h new file mode 100644 index 000000000000..150146531c0d --- /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/pinctrl_soc.h b/soc/bouffalolab/common/pinctrl_soc.h new file mode 100644 index 000000000000..39ab88acd914 --- /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_ */ 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 000000000000..3571353c64b6 --- /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); +} diff --git a/soc/bouffalolab/soc.yml b/soc/bouffalolab/soc.yml new file mode 100644 index 000000000000..8aafe0d43679 --- /dev/null +++ b/soc/bouffalolab/soc.yml @@ -0,0 +1,13 @@ +family: +- name: bouffalolab_bflb + series: + - name: bl60x + socs: + - name: bl602c00q2i + - name: bl602c20q2i + - name: bl602c20q2is + - name: bl602c40q2is + - name: bl602l10q2h + - name: bl602l20q2h + - name: bl604e20q2i +vendor: bflb diff --git a/west.yml b/west.yml index ca7b56f7e65f..9285c4c544f6 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 + revision: main + path: modules/hal/bouffalolab + remote: nandojve + groups: + - hal - name: hal_espressif revision: e52371024732a47a67fa9c889fbccd0aa6355f3a path: modules/hal/espressif