Skip to content

Commit 3ab2709

Browse files
dhsu-nordicrlubos
authored andcommitted
[nrf fromtree] soc: nordic: Add WICR generation tooling for nRF71
Add supporting scripts and build-system integration for WICR generation. Signed-off-by: Dhanoo Surasarang <dhanoo.surasarang@nordicsemi.no> (cherry picked from commit a9e88fa2fef73762910ddfbb35c419e852137139)
1 parent b28c0f9 commit 3ab2709

5 files changed

Lines changed: 220 additions & 0 deletions

File tree

soc/nordic/nrf71/Kconfig.sysbuild

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,12 @@ config SOC_NRF71_GENERATE_UICR
1616
When enabled, a UICR generator image is included in the build.
1717
This generates a standalone hex containing UICR values derived from
1818
the devicetree (nordic,nrf71-uicr binding).
19+
20+
config SOC_NRF71_GENERATE_WICR
21+
bool "Generate nRF71 WICR hex"
22+
depends on SOC_SERIES_NRF71
23+
default y
24+
help
25+
When enabled, a WICR generator image is included in the build.
26+
This generates a standalone hex containing WICR values derived from
27+
the devicetree (nordic,nrf-wicr binding).
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright (c) 2026 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
cmake_minimum_required(VERSION 3.20.0)
5+
6+
find_package(Zephyr
7+
COMPONENTS zephyr_default:boards
8+
REQUIRED HINTS $ENV{ZEPHYR_BASE}
9+
)
10+
11+
project(wicr LANGUAGES NONE)
12+
13+
# Override the runners.yaml path to use CMAKE_CURRENT_BINARY_DIR/zephyr
14+
# instead of PROJECT_BINARY_DIR, this ensures runners.yaml is generated
15+
# at <build>/wicr/zephyr where west expects it
16+
set(PROJECT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/zephyr)
17+
18+
set(gen_script ${CMAKE_CURRENT_LIST_DIR}/gen_wicr.py)
19+
set(wicr_hex ${PROJECT_BINARY_DIR}/zephyr.hex)
20+
21+
zephyr_get(DEFAULT_IMAGE_EDT_PICKLE SYSBUILD GLOBAL)
22+
23+
if(NOT DEFAULT_IMAGE_EDT_PICKLE)
24+
message(FATAL_ERROR
25+
"DEFAULT_IMAGE_EDT_PICKLE not found. "
26+
"The WICR generator must be built via sysbuild."
27+
)
28+
endif()
29+
30+
add_custom_command(
31+
OUTPUT ${wicr_hex}
32+
COMMAND ${PYTHON_EXECUTABLE} ${gen_script}
33+
--zephyr-base ${ZEPHYR_BASE}
34+
--edt-pickle ${DEFAULT_IMAGE_EDT_PICKLE}
35+
--output ${wicr_hex}
36+
DEPENDS ${DEFAULT_IMAGE_EDT_PICKLE} ${gen_script}
37+
COMMENT "Generating WICR hex: ${wicr_hex}"
38+
)
39+
40+
add_custom_target(gen_wicr ALL DEPENDS ${wicr_hex})
41+
42+
# Create the runners_yaml_props_target that flash system expects
43+
add_custom_target(runners_yaml_props_target)
44+
45+
# Copy over Kconfig and dts files from the main image
46+
get_filename_component(default_image_binary_dir ${DEFAULT_IMAGE_EDT_PICKLE} DIRECTORY)
47+
zephyr_file_copy(${default_image_binary_dir}/.config ${PROJECT_BINARY_DIR}/.config
48+
ONLY_IF_DIFFERENT
49+
)
50+
zephyr_file_copy(${default_image_binary_dir}/edt.pickle ${PROJECT_BINARY_DIR}/edt.pickle
51+
ONLY_IF_DIFFERENT
52+
)
53+
import_kconfig(CONFIG_ ${default_image_binary_dir}/.config)
54+
55+
# Manually include board configuration to enable automatic runners.yaml generation
56+
foreach(dir ${BOARD_DIRECTORIES})
57+
include(${dir}/board.cmake OPTIONAL)
58+
endforeach()
59+
60+
# Override hex_file after board.cmake to ensure it always flash its own output
61+
set_target_properties(runners_yaml_props_target PROPERTIES
62+
hex_file "zephyr.hex"
63+
)
64+
65+
# Include flash support to automatically generate runners.yaml
66+
include(${ZEPHYR_BASE}/cmake/flash/CMakeLists.txt)
67+
68+
# Silent unused variable warnings
69+
set(EXTRA_KCONFIG_TARGETS)
70+
set(FORCED_CONF_FILE)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Copyright 2026 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""
5+
Generate an Intel HEX file containing nRF71 WICR register values
6+
read from a Zephyr edtlib.EDT pickle.
7+
"""
8+
9+
import argparse
10+
import pickle
11+
import struct
12+
import sys
13+
from pathlib import Path
14+
15+
from intelhex import IntelHex
16+
17+
WICR_COMPATIBLE = "nordic,nrf-wicr"
18+
19+
20+
# ── Field table ──────────────────────────────────────────────────────
21+
#
22+
# Each entry describes one WICR register field configurable via DTS.
23+
#
24+
# property – DTS property name (must match the binding YAML)
25+
# offset – byte offset from WICR base
26+
# size_offset – (phandle only) byte offset for the companion SIZE register
27+
28+
WICR_FIELDS = [
29+
{"property": "firmware-lmacinitpc", "offset": 0x000},
30+
{"property": "firmware-umacinitpc", "offset": 0x004},
31+
{"property": "firmware-lmacrompatchaddr", "offset": 0x008},
32+
{"property": "firmware-umacrompatchaddr", "offset": 0x00C},
33+
{"property": "ipcconfig-commandmbox", "offset": 0x080, "size_offset": 0x084},
34+
{"property": "ipcconfig-eventmbox", "offset": 0x088, "size_offset": 0x08C},
35+
{"property": "ipcconfig-sparembox", "offset": 0x090, "size_offset": 0x094},
36+
]
37+
38+
39+
def setup_devicetree_path(zephyr_base):
40+
"""Add the devicetree package to sys.path so EDT can be unpickled."""
41+
42+
devicetree_path = Path(zephyr_base) / "scripts/dts/python-devicetree/src"
43+
if not devicetree_path.is_dir():
44+
sys.exit(f"Devicetree path does not exist: {devicetree_path}")
45+
sys.path.insert(0, str(devicetree_path))
46+
47+
48+
def put_word(ih, addr, word):
49+
"""Write a 32-bit little-endian word into the IntelHex."""
50+
51+
ih.puts(addr, struct.pack("<I", word))
52+
53+
54+
def parse_wicr(args):
55+
setup_devicetree_path(args.zephyr_base)
56+
57+
with open(args.edt_pickle, "rb") as f:
58+
edt = pickle.load(f)
59+
60+
wicr_nodes = edt.compat2okay.get(WICR_COMPATIBLE, [])
61+
if not wicr_nodes:
62+
IntelHex().write_hex_file(args.output)
63+
return
64+
65+
wicr = wicr_nodes[0]
66+
base = wicr.regs[0].addr
67+
68+
ih = IntelHex()
69+
wrote_any = False
70+
71+
for field in WICR_FIELDS:
72+
prop = wicr.props.get(field["property"])
73+
if prop is None:
74+
continue
75+
76+
target = prop.val
77+
if not target.regs:
78+
sys.exit(
79+
f"Phandle target for '{field['property']}' ({target.path}) has no reg property"
80+
)
81+
82+
put_word(ih, base + field["offset"], target.regs[0].addr)
83+
84+
size_offset = field.get("size_offset")
85+
if size_offset is not None:
86+
size_val = target.regs[0].size
87+
if size_val is None:
88+
sys.exit(
89+
f"Phandle target for '{field['property']}' "
90+
f"({target.path}) has no size in its reg property"
91+
)
92+
put_word(ih, base + size_offset, size_val)
93+
94+
wrote_any = True
95+
96+
if not wrote_any:
97+
IntelHex().write_hex_file(args.output)
98+
return
99+
100+
ih.write_hex_file(args.output)
101+
102+
103+
if __name__ == "__main__":
104+
parser = argparse.ArgumentParser(description=__doc__, allow_abbrev=False)
105+
parser.add_argument(
106+
"--zephyr-base",
107+
required=True,
108+
help="Path to the Zephyr base directory",
109+
)
110+
parser.add_argument(
111+
"--edt-pickle",
112+
required=True,
113+
help="Path to the main application's EDT pickle file",
114+
)
115+
parser.add_argument(
116+
"--output",
117+
required=True,
118+
help="Path for the output Intel HEX file",
119+
)
120+
args = parser.parse_args()
121+
122+
parse_wicr(args)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2026 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Add WICR generator as a utility image
5+
ExternalZephyrProject_Add(
6+
APPLICATION wicr
7+
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/gen_wicr
8+
)
9+
10+
sysbuild_add_dependencies(CONFIGURE wicr ${DEFAULT_IMAGE})
11+
12+
# Forward the default image's EDT pickle path to the WICR image.
13+
sysbuild_cache_set(VAR DEFAULT_IMAGE_EDT_PICKLE
14+
${CMAKE_BINARY_DIR}/${DEFAULT_IMAGE}/zephyr/edt.pickle
15+
)

soc/nordic/sysbuild.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,8 @@ endif()
3636

3737
if(SB_CONFIG_SOC_NRF71_GENERATE_UICR)
3838
include(${CMAKE_CURRENT_LIST_DIR}/nrf71/uicr/sysbuild.cmake)
39+
endif()
40+
41+
if(SB_CONFIG_SOC_NRF71_GENERATE_WICR)
42+
include(${CMAKE_CURRENT_LIST_DIR}/nrf71/wicr/sysbuild.cmake)
3943
endif()

0 commit comments

Comments
 (0)