diff --git a/dts/arm/silabs/siwg917.dtsi b/dts/arm/silabs/siwg917.dtsi new file mode 100644 index 00000000000..dca3192cfa9 --- /dev/null +++ b/dts/arm/silabs/siwg917.dtsi @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024-2025 Silicon Laboratories Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + chosen { + zephyr,flash = &flash0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + sram0: memory@0 { + compatible = "mmio-sram"; + reg = <0x00000000 DT_SIZE_K(191)>; + }; + + flash0: flash@8202000 { + compatible = "soc-nv-flash"; + reg = <0x8202000 DT_SIZE_K(2040)>; + write-block-size = <1>; + erase-block-size = <4096>; + }; + + soc { + clock0: clock@46000000 { + compatible = "silabs,siwx91x-clock"; + reg = <0x46000000 0x100>, + <0x46000800 0x100>, + <0x24041400 0x100>, + <0x24048000 0x200>; + #clock-cells = <1>; + status = "okay"; + }; + + ulpuart: uart@24041800 { + compatible = "ns16550"; + reg = <0x24041800 0x1000>; + interrupts = <12 0>; + reg-shift = <2>; + clocks = <&clock0 SIWX91X_CLK_ULP_UART>; + current-speed = <115200>; + status = "disabled"; + }; + + uart1: uart@44000000 { + compatible = "ns16550"; + reg = <0x44000000 0x1000>; + interrupts = <38 0>; + reg-shift = <2>; + clocks = <&clock0 SIWX91X_CLK_UART1>; + current-speed = <115200>; + status = "disabled"; + }; + + uart2: uart@45020000 { + compatible = "ns16550"; + reg = <0x45020000 0x1000>; + interrupts = <39 0>; + reg-shift = <2>; + clocks = <&clock0 SIWX91X_CLK_UART2>; + current-speed = <115200>; + status = "disabled"; + }; + + ulpi2c: i2c@24040000 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x24040000 0x100>; + interrupts = <13 0>; + interrupt-names = "i2c2"; + clocks = <&clock0 SIWX91X_CLK_ULP_I2C>; + status = "disabled"; + }; + + i2c0: i2c@44010000 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x44010000 0x100>; + interrupts = <42 0>; + interrupt-names = "i2c0"; + clocks = <&clock0 SIWX91X_CLK_I2C0>; + status = "disabled"; + }; + + i2c1: i2c@47040000 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x47040000 0x100>; + interrupts = <61 0>; + interrupt-names = "i2c1"; + clocks = <&clock0 SIWX91X_CLK_I2C1>; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <6>; +}; diff --git a/dts/arm/silabs/siwg917m111mgtba.dtsi b/dts/arm/silabs/siwg917m111mgtba.dtsi new file mode 100644 index 00000000000..b2c7d3a1b5c --- /dev/null +++ b/dts/arm/silabs/siwg917m111mgtba.dtsi @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Antmicro + * Copyright (c) 2024 Silicon Laboratories Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + compatible = "silabs,siwg917m111mgtba", "silabs,siwg917", + "silabs,siwx91x", "simple-bus"; + }; +}; + +&flash0 { + reg = <0x08202000 DT_SIZE_K(2048-8)>; +}; diff --git a/soc/silabs/CMakeLists.txt b/soc/silabs/CMakeLists.txt index 63d393a8d74..bce90b74766 100644 --- a/soc/silabs/CMakeLists.txt +++ b/soc/silabs/CMakeLists.txt @@ -1,9 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2017 Christian Taedcke -add_subdirectory(common) zephyr_include_directories(${SOC_FAMILY}) zephyr_include_directories(${SOC_FAMILY}/${SOC_SERIES}) -add_subdirectory_ifdef(CONFIG_SOC_FAMILY_SILABS_S2 silabs_s2) -add_subdirectory_ifdef(CONFIG_SOC_SERIES_SIM3U silabs_sim3/sim3u) +add_subdirectory(common) + +add_subdirectory_ifdef(CONFIG_SOC_FAMILY_SILABS_S2 silabs_s2) +add_subdirectory_ifdef(CONFIG_SOC_FAMILY_SILABS_SIWX91X silabs_siwx91x) +add_subdirectory_ifdef(CONFIG_SOC_SERIES_SIM3U silabs_sim3/sim3u) diff --git a/soc/silabs/Kconfig.soc b/soc/silabs/Kconfig.soc index 7b1174c6864..099b50d751d 100644 --- a/soc/silabs/Kconfig.soc +++ b/soc/silabs/Kconfig.soc @@ -5,6 +5,7 @@ config SOC_FAMILY default "silabs_s0" if SOC_FAMILY_SILABS_S0 default "silabs_s1" if SOC_FAMILY_SILABS_S1 default "silabs_s2" if SOC_FAMILY_SILABS_S2 + default "silabs_siwx91x" if SOC_FAMILY_SILABS_SIWX91X default "silabs_sim3" if SOC_FAMILY_SILABS_SIM3 rsource "*/Kconfig.soc" diff --git a/soc/silabs/silabs_siwx91x/CMakeLists.txt b/soc/silabs/silabs_siwx91x/CMakeLists.txt new file mode 100644 index 00000000000..7e3a8c84a16 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(siwg917) + +# Necessary to not overwrite NWP Firmware +math(EXPR FLASH_LOAD_ADDRESS "(${CONFIG_FLASH_BASE_ADDRESS}) + (${CONFIG_FLASH_LOAD_OFFSET})") + +set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/siwx91x_isp_prepare.py + --load-addr ${FLASH_LOAD_ADDRESS} + ${KERNEL_BIN_NAME} + ${KERNEL_BIN_NAME}.rps +) diff --git a/soc/silabs/silabs_siwx91x/Kconfig b/soc/silabs/silabs_siwx91x/Kconfig new file mode 100644 index 00000000000..a1f7371e9fb --- /dev/null +++ b/soc/silabs/silabs_siwx91x/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Antmicro +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_SILABS_SIWX91X + select ARM + select CPU_CORTEX_M4 + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select HAS_SILABS_WISECONNECT + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE diff --git a/soc/silabs/silabs_siwx91x/Kconfig.defconfig b/soc/silabs/silabs_siwx91x/Kconfig.defconfig new file mode 100644 index 00000000000..eeef3b6a753 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/Kconfig.defconfig @@ -0,0 +1,39 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_SILABS_SIWX91X + +config WISECONNECT_NETWORK_STACK + bool + select CMSIS_RTOS_V2 + select POLL + select DYNAMIC_THREAD + select THREAD_NAME + select THREAD_STACK_INFO + select THREAD_MONITOR + select INIT_STACKS + +if WISECONNECT_NETWORK_STACK + +# WiseConnect create threads with realtime priority. Default (10kHz) clock tick +# prevent proper use of the system with these threads. +config SYS_CLOCK_TICKS_PER_SEC + default 1024 + +config NUM_PREEMPT_PRIORITIES + default 56 + +config CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT + default 2 + +config CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE + default 1024 + +config CMSIS_V2_THREAD_MAX_STACK_SIZE + default 2048 + +endif # WISECONNECT_NETWORK_STACK + +rsource "*/Kconfig.defconfig" + +endif # SOC_FAMILY_SILABS_SIWX91X diff --git a/soc/silabs/silabs_siwx91x/Kconfig.soc b/soc/silabs/silabs_siwx91x/Kconfig.soc new file mode 100644 index 00000000000..f615334d2e4 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/Kconfig.soc @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_SILABS_SIWX91X + bool + +rsource "*/Kconfig.soc" diff --git a/soc/silabs/silabs_siwx91x/siwg917/CMakeLists.txt b/soc/silabs/silabs_siwx91x/siwg917/CMakeLists.txt new file mode 100644 index 00000000000..1fbd96d1ada --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwg917/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_SOC_SERIES_SIWG917 soc.c) + +set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/silabs/silabs_siwx91x/siwg917/Kconfig b/soc/silabs/silabs_siwx91x/siwg917/Kconfig new file mode 100644 index 00000000000..e9d4e75ff23 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwg917/Kconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Antmicro +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIWG917 + select SOC_EARLY_INIT_HOOK diff --git a/soc/silabs/silabs_siwx91x/siwg917/Kconfig.defconfig b/soc/silabs/silabs_siwx91x/siwg917/Kconfig.defconfig new file mode 100644 index 00000000000..9fa79429bcd --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwg917/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_SIWG917 + +config NUM_IRQS + default 99 + +config BUILD_OUTPUT_HEX + default y + +endif diff --git a/soc/silabs/silabs_siwx91x/siwg917/Kconfig.soc b/soc/silabs/silabs_siwx91x/siwg917/Kconfig.soc new file mode 100644 index 00000000000..c5e89582184 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwg917/Kconfig.soc @@ -0,0 +1,21 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIWG917 + bool + select SOC_FAMILY_SILABS_SIWX91X + help + SiWG917 Series MCU + +config SOC_PART_NUMBER_SIWG917M111MGTBA + bool + select SOC_SERIES_SIWG917 + +config SOC_SERIES + default "siwg917" if SOC_SERIES_SIWG917 + +config SOC + default "siwg917m111mgtba" if SOC_PART_NUMBER_SIWG917M111MGTBA + +config SOC_PART_NUMBER + default "SIWG917M111MGTBA" if SOC_PART_NUMBER_SIWG917M111MGTBA diff --git a/soc/silabs/silabs_siwx91x/siwg917/linker.ld b/soc/silabs/silabs_siwx91x/siwg917/linker.ld new file mode 100644 index 00000000000..b6e2b16cc91 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwg917/linker.ld @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Antmicro + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +SECTIONS +{ + .common_tcm_code : + { + *(.common_tcm_code*) + } > FLASH +} diff --git a/soc/silabs/silabs_siwx91x/siwg917/soc.c b/soc/silabs/silabs_siwx91x/siwg917/soc.c new file mode 100644 index 00000000000..139b7f3492a --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwg917/soc.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Antmicro + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#include "em_device.h" + +void soc_early_init_hook(void) +{ + SystemInit(); +} + +/* SiWx917's bootloader requires IRQn 32 to hold payload's entry point address. */ +extern void z_arm_reset(void); +Z_ISR_DECLARE_DIRECT(32, 0, z_arm_reset); diff --git a/soc/silabs/silabs_siwx91x/siwg917/soc.h b/soc/silabs/silabs_siwx91x/siwg917/soc.h new file mode 100644 index 00000000000..b96cf08e1a9 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwg917/soc.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SIWG917_SOC_H +#define SIWG917_SOC_H + +#include "si91x_device.h" + +#endif diff --git a/soc/silabs/silabs_siwx91x/siwx91x_isp_prepare.py b/soc/silabs/silabs_siwx91x/siwx91x_isp_prepare.py new file mode 100755 index 00000000000..3a217b0c217 --- /dev/null +++ b/soc/silabs/silabs_siwx91x/siwx91x_isp_prepare.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2023 Antmicro +# Copyright (c) 2024 Silicon Laboratories Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import struct +import sys + +import intelhex + + +# For reference: +# width=32 poly=0xd95eaae5 init=0 refin=true refout=true xorout=0 +def create_table() -> list[int]: + crc_table = [0] * 256 + for b in range(256): + register = b + for _ in range(8): + lsb = register & 1 + register >>= 1 + if lsb: + # Reflected polynomial: 0xd95eaae5 + register ^= 0xA7557A9B + crc_table[b] = register + return crc_table + + +def calc_crc32(data: bytes) -> int: + crc_table = create_table() + register = 0 + for b in data: + register = crc_table[(b ^ register) & 0xFF] ^ (register >> 8) + return register + + +def calc_checksum(data: bytes | bytearray, size: int, prev_sum: int) -> int: + # Truncate + data = data[:size] + # Zero-pad data to mul of 4 bytes + nzeros = ((len(data) + 3) // 4 * 4) - len(data) + data += b"\0" * nzeros + # Reinterpret data as LE u32 + ints = list(x[0] for x in struct.iter_unpack("> 32) + chk = (~chk) & 0xFFFFFFFF + return chk + + +def set_bits(x: int, off: int, size: int, field: int) -> int: + field = int(field) + mask = ((1 << size) - 1) << off + x &= ~mask + x |= (field << off) & mask + return x + + +def get_bootload_entry( + ctrl_len: int = 0, + ctrl_reserved: int = 0, + ctrl_spi_32bitmode: bool = False, + ctrl_release_ta_softreset: bool = False, + ctrl_start_from_rom_pc: bool = False, + ctrl_spi_8bitmode: bool = False, + ctrl_last_entry: bool = True, + dest_addr: int = 0, +) -> bytes: + # Format bootload_entry struct + ctrl = 0 + ctrl = set_bits(ctrl, 0, 24, ctrl_len) + ctrl = set_bits(ctrl, 24, 3, ctrl_reserved) + ctrl = set_bits(ctrl, 27, 1, ctrl_spi_32bitmode) + ctrl = set_bits(ctrl, 28, 1, ctrl_release_ta_softreset) + ctrl = set_bits(ctrl, 29, 1, ctrl_start_from_rom_pc) + ctrl = set_bits(ctrl, 30, 1, ctrl_spi_8bitmode) + ctrl = set_bits(ctrl, 31, 1, ctrl_last_entry) + return struct.pack(" bytes: + ret = b"" + ret += int(fixed_pattern).to_bytes(2, "little") + ret += int(offset).to_bytes(2, "little") + ret += int(ivt_offset).to_bytes(4, "little") + for i in range(7): + ret += get_bootload_entry(ctrl_last_entry=i == 0) + return ret + + +def get_fwupreq(flash_location: int, image_size: int) -> bytes: + # Field values + cflags = 1 + sha_type = 0 + magic_no = 0x900D900D + fw_version = 0 + # Initially CRC value is set to 0, then the CRC is calculated on the + # whole image (including fwupreq header), and injected here + crc = 0 + mic = [0, 0, 0, 0] + counter = 0 + rsvd = [0, 0, 0, 0, magic_no] + # Format + ret = b"" + ret += cflags.to_bytes(2, "little") + ret += sha_type.to_bytes(2, "little") + ret += magic_no.to_bytes(4, "little") + ret += image_size.to_bytes(4, "little") + ret += fw_version.to_bytes(4, "little") + ret += flash_location.to_bytes(4, "little") + ret += crc.to_bytes(4, "little") + for x in mic: + ret += x.to_bytes(4, "little") + ret += counter.to_bytes(4, "little") + for x in rsvd: + ret += x.to_bytes(4, "little") + return ret + + +def main(): + parser = argparse.ArgumentParser( + description="Converts raw binary output from Zephyr into an ISP binary for Silabs SiWx91x", + allow_abbrev=False, + ) + parser.add_argument( + "ifile", + metavar="INPUT.BIN", + help="Raw binary file to read", + type=argparse.FileType("rb"), + ) + parser.add_argument( + "ofile", + metavar="OUTPUT.BIN", + help="ISP binary file to write", + type=argparse.FileType("wb"), + ) + parser.add_argument( + "--load-addr", + metavar="ADDRESS", + help="Address at which the raw binary image begins in the memory", + type=lambda x: int(x, 0), + required=True, + ) + parser.add_argument( + "--out-hex", + metavar="FILE.HEX", + help="Generate Intel HEX output in addition to binary one", + type=argparse.FileType("w", encoding="ascii"), + ) + args = parser.parse_args() + + img = bytearray(args.ifile.read()) + + # Calculate and inject checksum + chk = calc_checksum(img, 236, 1) + print(f"ROM checksum: 0x{chk:08x}", file=sys.stderr) + img[236:240] = chk.to_bytes(4, "little") + + # Get bootloader header, pad to 4032 and glue it to the image payload + bl = bytearray(get_bootload_ds(4032, args.load_addr)) + padding = bytearray(4032 - len(bl)) + img = bl + padding + img + + # Get fwupreq header and glue it to the bootloader payload + fwupreq = bytearray(get_fwupreq(args.load_addr - 0x8001000, len(img))) + img = fwupreq + img + + # Calculate and inject CRC + crc = calc_crc32(img) + print(f"Image CRC: 0x{crc:08x}", file=sys.stderr) + img[20:24] = crc.to_bytes(4, "little") + + args.ofile.write(img) + + # If you want to compare this file with the .hex file generated by Zephyr, + # You have to reformat the Zephyr output: + # import intelhex + # hx = intelhex.IntelHex() + # hx.fromfile("zephyr.hex", "hex") + # hx.write_hex_file("zephyr.out.hex", byte_count=32) + if args.out_hex: + hx = intelhex.IntelHex() + # len(bl) + len(padding) + len(fwupreq) == 4096 + hx.frombytes(img, args.load_addr - 4096) + hx.write_hex_file(args.out_hex, byte_count=32) + + +if __name__ == "__main__": + main() diff --git a/soc/silabs/soc.yml b/soc/silabs/soc.yml index a2e5bd96930..b274cbda062 100644 --- a/soc/silabs/soc.yml +++ b/soc/silabs/soc.yml @@ -69,6 +69,11 @@ family: socs: - name: efr32mg29b140f1024im40 - name: efr32mg29b230f1024cm40 + - name: silabs_siwx91x + series: + - name: siwg917 + socs: + - name: siwg917m111mgtba - name: silabs_sim3 series: - name: sim3u