2525UICR_NODELABEL = "uicr"
2626# Nodelabel of the PERIPHCONF devicetree node, used to extract its location from the devicetree.
2727PERIPHCONF_NODELABEL = "periphconf_partition"
28+ # Nodelabel of the PERIPHCONF_RECOVERY devicetree node, used to extract its location
29+ # from the devicetree.
30+ PERIPHCONF_RECOVERY_NODELABEL = "periphconf_recovery_partition"
2831
2932# Common values for representing enabled/disabled in the UICR format.
3033ENABLED_VALUE = 0xFFFF_FFFF
@@ -67,13 +70,23 @@ class Protectedmem(c.LittleEndianStructure):
6770 ]
6871
6972
73+ class Periphconf (c .LittleEndianStructure ):
74+ _pack_ = 1
75+ _fields_ = [
76+ ("ENABLE" , c .c_uint32 ),
77+ ("ADDRESS" , c .c_uint32 ),
78+ ("MAXCOUNT" , c .c_uint32 ),
79+ ]
80+
81+
7082class Recovery (c .LittleEndianStructure ):
7183 _pack_ = 1
7284 _fields_ = [
7385 ("ENABLE" , c .c_uint32 ),
7486 ("PROCESSOR" , c .c_uint32 ),
7587 ("INITSVTOR" , c .c_uint32 ),
7688 ("SIZE4KB" , c .c_uint32 ),
89+ ("PERIPHCONF" , Periphconf ),
7790 ]
7891
7992
@@ -87,15 +100,6 @@ class Its(c.LittleEndianStructure):
87100 ]
88101
89102
90- class Periphconf (c .LittleEndianStructure ):
91- _pack_ = 1
92- _fields_ = [
93- ("ENABLE" , c .c_uint32 ),
94- ("ADDRESS" , c .c_uint32 ),
95- ("MAXCOUNT" , c .c_uint32 ),
96- ]
97-
98-
99103class Mpcconf (c .LittleEndianStructure ):
100104 _pack_ = 1
101105 _fields_ = [
@@ -115,11 +119,13 @@ class Uicr(c.LittleEndianStructure):
115119 ("APPROTECT" , Approtect ),
116120 ("ERASEPROTECT" , c .c_uint32 ),
117121 ("PROTECTEDMEM" , Protectedmem ),
118- ("RECOVERY " , Recovery ),
122+ ("RESERVED2 " , c . c_uint32 * 4 ),
119123 ("ITS" , Its ),
120- ("RESERVED2 " , c .c_uint32 * 7 ),
124+ ("RESERVED3 " , c .c_uint32 * 7 ),
121125 ("PERIPHCONF" , Periphconf ),
122126 ("MPCCONF" , Mpcconf ),
127+ ("RESERVED4" , c .c_uint32 ),
128+ ("RECOVERY" , Recovery ),
123129 ]
124130
125131
@@ -169,6 +175,12 @@ def main() -> None:
169175 type = argparse .FileType ("w" , encoding = "utf-8" ),
170176 help = "Path to write the generated PERIPHCONF HEX file to" ,
171177 )
178+ parser .add_argument (
179+ "--out-periphconf-recovery-hex" ,
180+ default = None ,
181+ type = argparse .FileType ("w" , encoding = "utf-8" ),
182+ help = "Path to write the generated PERIPHCONF_RECOVERY HEX file to" ,
183+ )
172184 args = parser .parse_args ()
173185
174186 try :
@@ -196,6 +208,36 @@ def main() -> None:
196208 padding_len = periphconf_size - len (periphconf_combined )
197209 periphconf_final = periphconf_combined + bytes ([0xFF for _ in range (padding_len )])
198210
211+ # Handle recovery periphconf partition if enabled
212+ periphconf_recovery_address = None
213+ periphconf_recovery_size = None
214+ periphconf_recovery_final = None
215+
216+ if kconfig .get ("CONFIG_NRF_HALTIUM_UICR_RECOVERY_PERIPHCONF" ) == "y" :
217+ try :
218+ periphconf_recovery_partition = edt .label2node [PERIPHCONF_RECOVERY_NODELABEL ]
219+ except LookupError as e :
220+ raise ScriptError (
221+ "Failed to find a PERIPHCONF_RECOVERY partition in the devicetree. "
222+ f"Expected a DT node with label '{ PERIPHCONF_RECOVERY_NODELABEL } '. "
223+ "This is required when "
224+ "CONFIG_NRF_HALTIUM_UICR_RECOVERY_PERIPHCONF is enabled."
225+ ) from e
226+
227+ flash_base_address_recovery = periphconf_recovery_partition .flash_controller .regs [
228+ 0
229+ ].addr
230+ periphconf_recovery_address = (
231+ flash_base_address_recovery + periphconf_recovery_partition .regs [0 ].addr
232+ )
233+ periphconf_recovery_size = periphconf_recovery_partition .regs [0 ].size
234+
235+ # Create a copy of the periphconf data for recovery at different location
236+ padding_len_recovery = periphconf_recovery_size - len (periphconf_combined )
237+ periphconf_recovery_final = periphconf_combined + bytes (
238+ [0xFF for _ in range (padding_len_recovery )]
239+ )
240+
199241 if kconfig .get ("CONFIG_NRF_HALTIUM_UICR_PERIPHCONF" ) == "y" :
200242 uicr .PERIPHCONF .ENABLE = ENABLED_VALUE
201243 uicr .PERIPHCONF .ADDRESS = periphconf_address
@@ -222,6 +264,11 @@ def main() -> None:
222264 size4kb = int (kconfig .get ("CONFIG_NRF_HALTIUM_UICR_RECOVERY_SIZE4KB" ), 0 )
223265 uicr .RECOVERY .SIZE4KB = size4kb
224266
267+ if kconfig .get ("CONFIG_NRF_HALTIUM_UICR_RECOVERY_PERIPHCONF" ) == "y" :
268+ uicr .RECOVERY .PERIPHCONF .ENABLE = ENABLED_VALUE
269+ uicr .RECOVERY .PERIPHCONF .ADDRESS = periphconf_recovery_address
270+ uicr .RECOVERY .PERIPHCONF .MAXCOUNT = math .floor (periphconf_recovery_size / 8 )
271+
225272 try :
226273 uicr_node = edt .label2node [UICR_NODELABEL ]
227274 except LookupError as e :
@@ -240,6 +287,13 @@ def main() -> None:
240287 periphconf_hex .frombytes (periphconf_final , offset = periphconf_address )
241288 periphconf_hex .write_hex_file (args .out_periphconf_hex )
242289
290+ if args .out_periphconf_recovery_hex is not None and periphconf_recovery_final is not None :
291+ periphconf_recovery_hex = IntelHex ()
292+ periphconf_recovery_hex .frombytes (
293+ periphconf_recovery_final , offset = periphconf_recovery_address
294+ )
295+ periphconf_recovery_hex .write_hex_file (args .out_periphconf_recovery_hex )
296+
243297 except ScriptError as e :
244298 print (f"Error: { e !s} " )
245299 sys .exit (1 )
@@ -268,8 +322,8 @@ def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes
268322 unique_values = {e .value for e in entries }
269323 if len (unique_values ) > 1 :
270324 raise ScriptError (
271- f"PERIPHCONF has conflicting values for register 0x { regptr :09_x } : "
272- + ", " .join ([f"0x{ val :09_x} " for val in unique_values ])
325+ f"PERIPHCONF has conflicting values for register "
326+ f"0x { regptr :09_x } : " + ", " .join ([f"0x{ val :09_x} " for val in unique_values ])
273327 )
274328 deduplicated_periphconf .append (entries [0 ])
275329
0 commit comments