soc: silabs: Introduce new SoC SiWG917

Introduce minimal support for Silicon Labs SiWx91x family. SiWx91x
provide many device and especially Bluetooth and Wifi connectivity. This
patch prepare Zephyr to receive further drivers.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
This commit is contained in:
Jérôme Pouiller 2025-01-30 16:39:14 +01:00 committed by Benjamin Cabé
commit aac0b343b5
17 changed files with 500 additions and 3 deletions

115
dts/arm/silabs/siwg917.dtsi Normal file
View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2024-2025 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <arm/armv7-m.dtsi>
#include <zephyr/dt-bindings/clock/silabs/siwx91x-clock.h>
/ {
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>;
};

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 Antmicro
* Copyright (c) 2024 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <mem.h>
#include <silabs/siwg917.dtsi>
/ {
soc {
compatible = "silabs,siwg917m111mgtba", "silabs,siwg917",
"silabs,siwx91x", "simple-bus";
};
};
&flash0 {
reg = <0x08202000 DT_SIZE_K(2048-8)>;
};

View file

@ -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)

View file

@ -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"

View file

@ -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
)

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,7 @@
# Copyright (c) 2023 Antmicro
# SPDX-License-Identifier: Apache-2.0
config SOC_FAMILY_SILABS_SIWX91X
bool
rsource "*/Kconfig.soc"

View file

@ -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 "")

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2023 Antmicro
* Copyright (c) 2024 Silicon Laboratories Inc.
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/arch/arm/cortex_m/scripts/linker.ld>
SECTIONS
{
.common_tcm_code :
{
*(.common_tcm_code*)
} > FLASH
}

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2023 Antmicro
* Copyright (c) 2024 Silicon Laboratories Inc.
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/sw_isr_table.h>
#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);

View file

@ -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

View file

@ -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("<I", data))
# Sum
chk = prev_sum + sum(ints)
# Convert to u32 and account each overflow as 1"s complement addition
chk = (chk & 0xFFFFFFFF) + (chk >> 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("<II", ctrl, dest_addr)
def get_bootload_ds(offset: int, ivt_offset: int, fixed_pattern: int = 0x5AA5) -> 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()

View file

@ -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