Skip to content

Commit dc098ca

Browse files
committed
[nrf toup] nordic: Reorganize how gen_uicr.py is invoked
Reorganize how gen_uicr.py is invoked Ref: NCSDK-NONE Signed-off-by: Sebastian Bøe <[email protected]>
1 parent 793e93e commit dc098ca

File tree

13 files changed

+191
-143
lines changed

13 files changed

+191
-143
lines changed

scripts/west_commands/runners/nrf_common.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -433,26 +433,6 @@ def program_hex(self):
433433
core='Application',
434434
)
435435

436-
if self.build_conf.getboolean("CONFIG_NRF_HALTIUM_GENERATE_UICR"):
437-
zephyr_build_dir = Path(self.cfg.build_dir) / 'zephyr'
438-
439-
self.op_program(
440-
str(zephyr_build_dir / 'uicr.hex'),
441-
'ERASE_NONE',
442-
None,
443-
defer=True,
444-
core='Application',
445-
)
446-
447-
if self.build_conf.getboolean("CONFIG_NRF_HALTIUM_UICR_PERIPHCONF"):
448-
self.op_program(
449-
str(zephyr_build_dir / 'periphconf.hex'),
450-
'ERASE_NONE',
451-
None,
452-
defer=True,
453-
core='Application',
454-
)
455-
456436
if not self.erase and regtool_generated_uicr:
457437
self.exec_op('erase', core=core, kind='uicr')
458438
else:

soc/nordic/Kconfig.sysbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
config HAS_NORDIC_VPR_LAUNCHER_IMAGE
55
bool
66

7+
rsource "common/uicr/Kconfig.sysbuild"
78
rsource "common/vpr/Kconfig.sysbuild"
89
orsource "*/Kconfig.sysbuild"

soc/nordic/common/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
add_subdirectory_ifdef(CONFIG_RISCV_CORE_NORDIC_VPR vpr)
55

6-
if(CONFIG_NRF_PERIPHCONF_SECTION OR CONFIG_NRF_HALTIUM_GENERATE_UICR)
6+
if(CONFIG_NRF_PERIPHCONF_SECTION)
77
add_subdirectory(uicr)
88
endif()
99

soc/nordic/common/uicr/CMakeLists.txt

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,3 @@
44
if(CONFIG_NRF_PERIPHCONF_SECTION)
55
zephyr_linker_sources(SECTIONS uicr.ld)
66
endif()
7-
8-
if(CONFIG_NRF_HALTIUM_GENERATE_UICR)
9-
if(CONFIG_NRF_PERIPHCONF_SECTION)
10-
set(in_periphconf_elf_arg
11-
--in-periphconf-elf $<TARGET_FILE:${ZEPHYR_LINK_STAGE_EXECUTABLE}>
12-
)
13-
endif()
14-
15-
if(CONFIG_NRF_HALTIUM_UICR_PERIPHCONF)
16-
set(periphconf_hex_file ${PROJECT_BINARY_DIR}/periphconf.hex)
17-
set(out_periphconf_hex_arg
18-
--out-periphconf-hex ${periphconf_hex_file}
19-
)
20-
list(APPEND optional_byproducts ${periphconf_hex_file})
21-
endif()
22-
23-
set(uicr_hex_file ${PROJECT_BINARY_DIR}/uicr.hex)
24-
set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
25-
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${ZEPHYR_BASE}/scripts/dts/python-devicetree/src
26-
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/gen_uicr.py
27-
--in-config ${DOTCONFIG}
28-
--in-edt-pickle ${EDT_PICKLE}
29-
${in_periphconf_elf_arg}
30-
${out_periphconf_hex_arg}
31-
--out-uicr-hex ${uicr_hex_file}
32-
)
33-
set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts
34-
${uicr_hex_file} ${optional_byproducts}
35-
)
36-
endif()

soc/nordic/common/uicr/Kconfig

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,9 @@
11
# Copyright (c) 2025 Nordic Semiconductor ASA
22
# SPDX-License-Identifier: Apache-2.0
33

4-
config NRF_HALTIUM_GENERATE_UICR
5-
bool "Generate UICR file"
6-
depends on SOC_NRF54H20_CPUAPP
7-
default y
8-
help
9-
Generate UICR HEX file.
10-
11-
if NRF_HALTIUM_GENERATE_UICR
12-
13-
config NRF_HALTIUM_UICR_PERIPHCONF
14-
bool "Initialize global domain peripherals"
15-
default y
16-
help
17-
Generates a blob containing static global domain peripheral initialization
18-
values extracted from the build artifacts, and configures UICR.PERIPHCONF
19-
to point at the blob. The initialization values are then loaded ahead of
20-
ahead of the application boot.
21-
22-
endif
23-
244
config NRF_PERIPHCONF_SECTION
255
bool "Populate global peripheral initialization section"
26-
default y if SOC_NRF54H20_CPUAPP
6+
default y if SOC_NRF54H20_CPUAPP || SOC_NRF54H20_CPURAD
277
depends on LINKER_DEVNULL_SUPPORT
288
imply LINKER_DEVNULL_MEMORY
299
help
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
config NRF_HALTIUM_GENERATE_UICR
2+
bool "Generate UICR file"
3+
depends on SOC_SERIES_NRF54HX
4+
default y
5+
help
6+
Generate UICR HEX file.
7+

soc/nordic/common/uicr/gen_uicr.py

Lines changed: 30 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@
88
import argparse
99
import ctypes as c
1010
import math
11-
import pickle
12-
import re
1311
import sys
14-
from collections import defaultdict
1512
from itertools import groupby
1613

1714
from elftools.elf.elffile import ELFFile
@@ -25,11 +22,6 @@
2522
# Must match the name used in the linker script.
2623
PERIPHCONF_SECTION = "uicr_periphconf_entry"
2724

28-
# Expected nodelabel of the UICR devicetree node, used to extract its location from the devicetree.
29-
UICR_NODELABEL = "uicr"
30-
# Nodelabel of the PERIPHCONF devicetree node, used to extract its location from the devicetree.
31-
PERIPHCONF_NODELABEL = "periphconf_partition"
32-
3325
# Common values for representing enabled/disabled in the UICR format.
3426
ENABLED_VALUE = 0xFFFF_FFFF
3527
DISABLED_VALUE = 0xBD23_28A8
@@ -141,18 +133,6 @@ def main() -> None:
141133
"peripherals, and to protect the device in various ways."
142134
),
143135
)
144-
parser.add_argument(
145-
"--in-config",
146-
required=True,
147-
type=argparse.FileType("r"),
148-
help="Path to the .config file from the application build",
149-
)
150-
parser.add_argument(
151-
"--in-edt-pickle",
152-
required=True,
153-
type=argparse.FileType("rb"),
154-
help="Path to the edt.pickle file from the application build",
155-
)
156136
parser.add_argument(
157137
"--in-periphconf-elf",
158138
dest="in_periphconf_elfs",
@@ -169,13 +149,25 @@ def main() -> None:
169149
"--out-uicr-hex",
170150
required=True,
171151
type=argparse.FileType("w", encoding="utf-8"),
172-
help="Path to write the generated UICR HEX file to",
152+
help="Path to write the generated merged UICR+PERIPHCONF HEX file to (typically zephyr.hex)",
173153
)
174154
parser.add_argument(
175-
"--out-periphconf-hex",
155+
"--periphconf-address",
176156
default=None,
177-
type=argparse.FileType("w", encoding="utf-8"),
178-
help="Path to write the generated PERIPHCONF HEX file to",
157+
type=lambda s: int(s, 0),
158+
help="Absolute flash address of the PERIPHCONF partition (decimal or 0x-prefixed hex)",
159+
)
160+
parser.add_argument(
161+
"--periphconf-size",
162+
default=None,
163+
type=lambda s: int(s, 0),
164+
help="Size in bytes of the PERIPHCONF partition (decimal or 0x-prefixed hex)",
165+
)
166+
parser.add_argument(
167+
"--uicr-address",
168+
required=True,
169+
type=lambda s: int(s, 0),
170+
help="Absolute flash address of the UICR region (decimal or 0x-prefixed hex)",
179171
)
180172
args = parser.parse_args()
181173

@@ -186,49 +178,27 @@ def main() -> None:
186178
uicr.VERSION.MAJOR = UICR_FORMAT_VERSION_MAJOR
187179
uicr.VERSION.MINOR = UICR_FORMAT_VERSION_MINOR
188180

189-
kconfig_str = args.in_config.read()
190-
kconfig = parse_kconfig(kconfig_str)
191-
192-
edt = pickle.load(args.in_edt_pickle)
181+
# Create a single hex object that will contain both UICR and periphconf data
182+
merged_hex = IntelHex()
193183

194-
try:
195-
periphconf_partition = edt.label2node[PERIPHCONF_NODELABEL]
196-
except LookupError as e:
197-
raise ScriptError(
198-
"Failed to find a PERIPHCONF partition in the devicetree. "
199-
f"Expected a DT node with label '{PERIPHCONF_NODELABEL}'."
200-
) from e
184+
if args.in_periphconf_elfs: # Check if periphconf data is provided
185+
periphconf_combined = extract_and_combine_periphconfs(args.in_periphconf_elfs)
201186

202-
flash_base_address = periphconf_partition.flash_controller.regs[0].addr
203-
periphconf_address = flash_base_address + periphconf_partition.regs[0].addr
204-
periphconf_size = periphconf_partition.regs[0].size
187+
padding_len = args.periphconf_size - len(periphconf_combined)
188+
periphconf_final = periphconf_combined + bytes([0xFF for _ in range(padding_len)])
205189

206-
periphconf_combined = extract_and_combine_periphconfs(args.in_periphconf_elfs)
207-
padding_len = periphconf_size - len(periphconf_combined)
208-
periphconf_final = periphconf_combined + bytes([0xFF for _ in range(padding_len)])
190+
# Add periphconf data to the merged hex
191+
merged_hex.frombytes(periphconf_final, offset=args.periphconf_address)
209192

210-
if kconfig.get("CONFIG_NRF_HALTIUM_UICR_PERIPHCONF") == "y":
211193
uicr.PERIPHCONF.ENABLE = ENABLED_VALUE
212-
uicr.PERIPHCONF.ADDRESS = periphconf_address
213-
uicr.PERIPHCONF.MAXCOUNT = math.floor(periphconf_size / 8)
214-
215-
try:
216-
uicr_node = edt.label2node[UICR_NODELABEL]
217-
except LookupError as e:
218-
raise ScriptError(
219-
"Failed to find UICR node in the devicetree. "
220-
f"Expected a DT node with label '{UICR_NODELABEL}'."
221-
) from e
194+
uicr.PERIPHCONF.ADDRESS = args.periphconf_address
195+
uicr.PERIPHCONF.MAXCOUNT = math.floor(args.periphconf_size / 8)
222196

223-
uicr_hex = IntelHex()
224-
uicr_hex.frombytes(bytes(uicr), offset=uicr_node.regs[0].addr)
197+
# Add UICR data to the merged hex
198+
merged_hex.frombytes(bytes(uicr), offset=args.uicr_address)
225199

226-
uicr_hex.write_hex_file(args.out_uicr_hex)
227-
228-
if args.out_periphconf_hex is not None:
229-
periphconf_hex = IntelHex()
230-
periphconf_hex.frombytes(periphconf_final, offset=periphconf_address)
231-
periphconf_hex.write_hex_file(args.out_periphconf_hex)
200+
# Write the merged hex file containing both UICR and periphconf data
201+
merged_hex.write_hex_file(args.out_uicr_hex)
232202

233203
except ScriptError as e:
234204
print(f"Error: {e!s}")
@@ -270,16 +240,5 @@ def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes
270240
return bytes(final_periphconf)
271241

272242

273-
def parse_kconfig(content: str) -> dict[str, str | None]:
274-
result = defaultdict(None)
275-
match_iter = re.finditer(
276-
r"^(?P<config>(SB_)?CONFIG_[^=\s]+)=(?P<value>[^\s#])+$", content, re.MULTILINE
277-
)
278-
for match in match_iter:
279-
result[match["config"]] = match["value"]
280-
281-
return result
282-
283-
284243
if __name__ == "__main__":
285244
main()
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
#
3+
# The code in this CMakeLists.txt constructs the arguments for gen_uicr.py
4+
# and creates a flashable zephyr.hex file containing UICR data (no C code compiled)
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
# Instead of adding all of Zephyr we add just the subset that is
10+
# required to generate uicr.hex.
11+
#
12+
# The generation of uicr.hex is configured by this image, so we
13+
# include modules from zephyr_default up until kconfig.
14+
15+
find_package(Zephyr
16+
COMPONENTS zephyr_default:kconfig
17+
REQUIRED HINTS $ENV{ZEPHYR_BASE}
18+
)
19+
20+
project(uicr)
21+
22+
# Use CMAKE_VERBOSE_MAKEFILE to silence an unused-variable warning.
23+
if(CMAKE_VERBOSE_MAKEFILE)
24+
endif()
25+
26+
set(periphconf_args)
27+
set(periphconf_elfs)
28+
set(zephyr_hex_file ${APPLICATION_BINARY_DIR}/zephyr/zephyr.hex)
29+
30+
# Compute UICR absolute address from this image's devicetree
31+
dt_nodelabel(uicr_path NODELABEL "uicr")
32+
33+
if(NOT DEFINED uicr_path)
34+
message(FATAL_ERROR "uicr node not found in devicetree")
35+
endif()
36+
37+
dt_reg_addr(UICR_ADDRESS PATH ${uicr_path})
38+
39+
if(NOT DEFINED UICR_ADDRESS)
40+
message(FATAL_ERROR "Failed to read UICR address from DT")
41+
endif()
42+
43+
if(CONFIG_UICR_SAMPLE_GENERATE_PERIPHCONF)
44+
# gen_uicr.py parses all zephyr.elf files. To find these files (which
45+
# have not been built yet) we scan sibling build directories for
46+
# zephyr.dts
47+
get_filename_component(SYSBUILD_DIR ${APPLICATION_BINARY_DIR} DIRECTORY)
48+
file(GLOB _siblings LIST_DIRECTORIES true "${SYSBUILD_DIR}/*")
49+
foreach(_dir ${_siblings})
50+
get_filename_component(_name ${_dir} NAME)
51+
if(_name STREQUAL "uicr")
52+
# This image is an exception to the rule. It has a zephyr.dts, but
53+
# no zephyr.elf
54+
continue()
55+
endif()
56+
57+
if(EXISTS ${_dir}/zephyr/zephyr.dts)
58+
list(APPEND periphconf_elfs ${_dir}/zephyr/zephyr.elf)
59+
endif()
60+
endforeach()
61+
62+
# Compute PERIPHCONF absolute address and size from this image's devicetree
63+
dt_nodelabel(periph_path NODELABEL "periphconf_partition")
64+
if(NOT DEFINED periph_path)
65+
message(FATAL_ERROR "periphconf_partition not found in devicetree")
66+
endif()
67+
68+
dt_reg_addr(PERIPHCONF_OFFSET PATH ${periph_path})
69+
dt_reg_size(PERIPHCONF_SIZE PATH ${periph_path})
70+
71+
if(NOT DEFINED PERIPHCONF_OFFSET OR NOT DEFINED PERIPHCONF_SIZE)
72+
message(FATAL_ERROR "Failed to read periphconf addresses from DT")
73+
endif()
74+
75+
# Calculate absolute periphconf address
76+
math(EXPR PERIPHCONF_ADDRESS "${CONFIG_FLASH_BASE_ADDRESS} + ${PERIPHCONF_OFFSET}" OUTPUT_FORMAT HEXADECIMAL)
77+
78+
# Set up periphconf arguments for gen_uicr.py
79+
list(APPEND periphconf_args --periphconf-address ${PERIPHCONF_ADDRESS})
80+
list(APPEND periphconf_args --periphconf-size ${PERIPHCONF_SIZE})
81+
82+
foreach(elf ${periphconf_elfs})
83+
list(APPEND periphconf_args --in-periphconf-elf ${elf})
84+
endforeach()
85+
endif(CONFIG_UICR_SAMPLE_GENERATE_PERIPHCONF)
86+
87+
# Generate zephyr.hex file
88+
add_custom_command(
89+
OUTPUT ${zephyr_hex_file}
90+
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${ZEPHYR_BASE}/scripts/dts/python-devicetree/src
91+
${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/soc/nordic/common/uicr/gen_uicr.py
92+
--uicr-address ${UICR_ADDRESS}
93+
--out-uicr-hex ${zephyr_hex_file}
94+
${periphconf_args}
95+
DEPENDS ${periphconf_elfs}
96+
WORKING_DIRECTORY ${APPLICATION_BINARY_DIR}
97+
COMMENT "Using gen_uicr.py to generate ${zephyr_hex_file}"
98+
)
99+
100+
# Add zephyr subdirectory to handle flash configuration with correct paths
101+
add_subdirectory(zephyr)
102+
103+
add_custom_target(gen_uicr ALL DEPENDS ${zephyr_hex_file})
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
source "Kconfig.zephyr"
4+
5+
menu "UICR generator options"
6+
7+
config UICR_SAMPLE_GENERATE_PERIPHCONF
8+
bool "Generate PERIPHCONF hex alongside UICR"
9+
default y
10+
help
11+
When enabled, the UICR generator will emit periphconf.hex in addition to uicr.hex.
12+
13+
endmenu

soc/nordic/common/uicr/gen_uicr/prj.conf

Whitespace-only changes.

0 commit comments

Comments
 (0)