Skip to content

Commit 5562195

Browse files
committed
[nrf toup] nordic: Reorganize how gen_uicr.py is invoked
Reorganize how gen_uicr.py is invoked. Instead of invoking it from one of the Zephyr images we invoke it from a new special Zephyr image called uicr. This uicr Zephyr image is flashed in the same way as normal Zephyr images so special handling in the runner is no longer necessary. gen_uicr.py has been modified to no longer create a seperate hex file for periphconf as the runner infrastructure expects to only flash one hex file. Also, we simplify gen_uicr.py by moving parsing of Kconfig/DT from gen_uicr.py to CMake. Ref: NCSDK-NONE Signed-off-by: Sebastian Bøe <[email protected]>
1 parent 8f6f73e commit 5562195

File tree

13 files changed

+222
-140
lines changed

13 files changed

+222
-140
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: 55 additions & 68 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",
@@ -165,17 +145,40 @@ def main() -> None:
165145
"by ascending address and cleared of duplicate entries."
166146
),
167147
)
148+
parser.add_argument(
149+
"--out-merged-hex",
150+
required=True,
151+
type=argparse.FileType("w", encoding="utf-8"),
152+
help="Path to write the merged UICR+PERIPHCONF HEX file to",
153+
)
168154
parser.add_argument(
169155
"--out-uicr-hex",
170156
required=True,
171157
type=argparse.FileType("w", encoding="utf-8"),
172-
help="Path to write the generated UICR HEX file to",
158+
help="Path to write the UICR-only HEX file to",
173159
)
174160
parser.add_argument(
175161
"--out-periphconf-hex",
176-
default=None,
177162
type=argparse.FileType("w", encoding="utf-8"),
178-
help="Path to write the generated PERIPHCONF HEX file to",
163+
help="Path to write the PERIPHCONF-only HEX file to",
164+
)
165+
parser.add_argument(
166+
"--periphconf-address",
167+
default=None,
168+
type=lambda s: int(s, 0),
169+
help="Absolute flash address of the PERIPHCONF partition (decimal or 0x-prefixed hex)",
170+
)
171+
parser.add_argument(
172+
"--periphconf-size",
173+
default=None,
174+
type=lambda s: int(s, 0),
175+
help="Size in bytes of the PERIPHCONF partition (decimal or 0x-prefixed hex)",
176+
)
177+
parser.add_argument(
178+
"--uicr-address",
179+
required=True,
180+
type=lambda s: int(s, 0),
181+
help="Absolute flash address of the UICR region (decimal or 0x-prefixed hex)",
179182
)
180183
args = parser.parse_args()
181184

@@ -186,48 +189,43 @@ def main() -> None:
186189
uicr.VERSION.MAJOR = UICR_FORMAT_VERSION_MAJOR
187190
uicr.VERSION.MINOR = UICR_FORMAT_VERSION_MINOR
188191

189-
kconfig_str = args.in_config.read()
190-
kconfig = parse_kconfig(kconfig_str)
192+
# Create separate hex objects
193+
merged_hex = IntelHex()
194+
uicr_hex = IntelHex()
195+
periphconf_hex = IntelHex()
191196

192-
edt = pickle.load(args.in_edt_pickle)
197+
# Always add UICR data
198+
uicr_data = bytes(uicr)
199+
uicr_hex.frombytes(uicr_data, offset=args.uicr_address)
200+
merged_hex.frombytes(uicr_data, offset=args.uicr_address)
193201

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
202+
if args.in_periphconf_elfs: # Check if periphconf data is provided
203+
periphconf_combined = extract_and_combine_periphconfs(args.in_periphconf_elfs)
201204

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
205+
padding_len = args.periphconf_size - len(periphconf_combined)
206+
periphconf_final = periphconf_combined + bytes([0xFF for _ in range(padding_len)])
205207

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)])
208+
# Add periphconf data to separate and merged hex files
209+
periphconf_hex.frombytes(periphconf_final, offset=args.periphconf_address)
210+
merged_hex.frombytes(periphconf_final, offset=args.periphconf_address)
209211

210-
if kconfig.get("CONFIG_NRF_HALTIUM_UICR_PERIPHCONF") == "y":
211212
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
222-
223-
uicr_hex = IntelHex()
224-
uicr_hex.frombytes(bytes(uicr), offset=uicr_node.regs[0].addr)
225-
213+
uicr.PERIPHCONF.ADDRESS = args.periphconf_address
214+
uicr.PERIPHCONF.MAXCOUNT = math.floor(args.periphconf_size / 8)
215+
216+
# Update UICR hex with the modified UICR data
217+
uicr_data = bytes(uicr)
218+
uicr_hex = IntelHex() # Reset and rebuild with updated UICR
219+
uicr_hex.frombytes(uicr_data, offset=args.uicr_address)
220+
merged_hex = IntelHex() # Reset and rebuild merged
221+
merged_hex.frombytes(uicr_data, offset=args.uicr_address)
222+
merged_hex.frombytes(periphconf_final, offset=args.periphconf_address)
223+
224+
# Write the three hex files
225+
merged_hex.write_hex_file(args.out_merged_hex)
226226
uicr_hex.write_hex_file(args.out_uicr_hex)
227227

228-
if args.out_periphconf_hex is not None:
229-
periphconf_hex = IntelHex()
230-
periphconf_hex.frombytes(periphconf_final, offset=periphconf_address)
228+
if args.out_periphconf_hex and args.in_periphconf_elfs:
231229
periphconf_hex.write_hex_file(args.out_periphconf_hex)
232230

233231
except ScriptError as e:
@@ -270,16 +268,5 @@ def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes
270268
return bytes(final_periphconf)
271269

272270

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-
284271
if __name__ == "__main__":
285272
main()

0 commit comments

Comments
 (0)