scripts: west: runners: nrfjprog: add basic support for nRF54H series
Add basic support to flash application and/or radio core for nRF54H
series. Note that features like merged hexes present in nRF53 series is
not supported.
Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py
index 93871d8..76662c7 100644
--- a/scripts/west_commands/runners/nrf_common.py
+++ b/scripts/west_commands/runners/nrf_common.py
@@ -24,11 +24,26 @@
ErrNotAvailableBecauseProtection = 24
ErrVerify = 25
+UICR_RANGES = {
+ 'NRF53_FAMILY': {
+ 'NRFDL_DEVICE_CORE_APPLICATION': (0x00FF8000, 0x00FF8800),
+ 'NRFDL_DEVICE_CORE_NETWORK': (0x01FF8000, 0x01FF8800),
+ },
+ 'NRF54H_FAMILY': {
+ 'NRFDL_DEVICE_CORE_APPLICATION': (0x0FFF8000, 0x0FFF8800),
+ 'NRFDL_DEVICE_CORE_NETWORK': (0x0FFFA000, 0x0FFFA800),
+ },
+ 'NRF91_FAMILY': {
+ 'NRFDL_DEVICE_CORE_APPLICATION': (0x00FF8000, 0x00FF8800),
+ }
+}
+
class NrfBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end base class for nrf tools.'''
def __init__(self, cfg, family, softreset, dev_id, erase=False,
- reset=True, tool_opt=[], force=False, recover=False):
+ reset=True, tool_opt=[], force=False, recover=False,
+ erase_all_uicrs=False):
super().__init__(cfg)
self.hex_ = cfg.hex_file
if family and not family.endswith('_FAMILY'):
@@ -40,6 +55,7 @@
self.reset = bool(reset)
self.force = force
self.recover = bool(recover)
+ self.erase_all_uicrs = bool(erase_all_uicrs)
self.tool_opt = []
for opts in [shlex.split(opt) for opt in tool_opt]:
@@ -59,7 +75,8 @@
@classmethod
def do_add_parser(cls, parser):
parser.add_argument('--nrf-family',
- choices=['NRF51', 'NRF52', 'NRF53', 'NRF54L', 'NRF91'],
+ choices=['NRF51', 'NRF52', 'NRF53', 'NRF54L',
+ 'NRF54H', 'NRF91'],
help='''MCU family; still accepted for
compatibility only''')
parser.add_argument('--softreset', required=False,
@@ -75,6 +92,11 @@
help='''erase all user available non-volatile
memory and disable read back protection before
flashing (erases flash for both cores on nRF53)''')
+ parser.add_argument('--erase-all-uicrs', required=False,
+ action='store_true',
+ help='''Erase all UICR registers before flashing
+ (nRF54H only). When not set, only UICR registers
+ present in the hex file will be erased.''')
parser.set_defaults(reset=True)
@@ -163,6 +185,8 @@
self.family = 'NRF53_FAMILY'
elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54LX'):
self.family = 'NRF54L_FAMILY'
+ elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54HX'):
+ self.family = 'NRF54H_FAMILY'
elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF91X'):
self.family = 'NRF91_FAMILY'
else:
@@ -174,21 +198,15 @@
return True
return False
- def hex_has_uicr_content(self):
- # A map from SoCs which need this check to their UICR address
- # ranges. If self.family isn't in here, do nothing.
- uicr_ranges = {
- 'NRF53_FAMILY': ((0x00FF8000, 0x00FF8800),
- (0x01FF8000, 0x01FF8800)),
- 'NRF91_FAMILY': ((0x00FF8000, 0x00FF8800),),
- }
+ def hex_get_uicrs(self):
+ hex_uicrs = {}
- if self.family not in uicr_ranges:
- return
+ if self.family in UICR_RANGES:
+ for uicr_core, uicr_range in UICR_RANGES[self.family].items():
+ if self.hex_refers_region(*uicr_range):
+ hex_uicrs[uicr_core] = uicr_range
- for region_start, region_end in uicr_ranges[self.family]:
- if self.hex_refers_region(region_start, region_end):
- return True
+ return hex_uicrs
def flush(self, force=False):
try:
@@ -213,7 +231,7 @@
# If there are data in the UICR region it is likely that the
# verify failed du to the UICR not been erased before, so giving
# a warning here will hopefully enhance UX.
- if self.hex_has_uicr_content():
+ if self.hex_get_uicrs():
self.logger.warning(
'The hex file contains data placed in the UICR, which '
'may require a full erase before reprogramming. Run '
@@ -266,11 +284,24 @@
if self.family == 'NRF53_FAMILY':
# nRF53 requires special treatment due to the extra coprocessor.
self.program_hex_nrf53(erase_arg, qspi_erase_opt)
+ elif self.family == 'NRF54H_FAMILY':
+ self.program_hex_nrf54h()
else:
self.op_program(self.hex_, erase_arg, qspi_erase_opt, defer=True)
self.flush(force=False)
+ def program_hex_nrf54h(self):
+ if self.erase_all_uicrs:
+ uicrs = UICR_RANGES['NRF54H_FAMILY']
+ else:
+ uicrs = self.hex_get_uicrs()
+
+ for uicr_core, range in uicrs.items():
+ self.exec_op('erasepage', defer=True, core=uicr_core, page=range[0])
+
+ self.op_program(self.hex_, 'NO_ERASE', None, defer=True)
+
def program_hex_nrf53(self, erase_arg, qspi_erase_opt):
# program_hex() helper for nRF53.
diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py
index c1eebd3..723080d 100644
--- a/scripts/west_commands/runners/nrfjprog.py
+++ b/scripts/west_commands/runners/nrfjprog.py
@@ -32,7 +32,8 @@
args.dev_id, erase=args.erase,
reset=args.reset,
tool_opt=args.tool_opt, force=args.force,
- recover=args.recover)
+ recover=args.recover,
+ erase_all_uicrs=args.erase_all_uicrs)
def do_get_boards(self):
snrs = self.check_output(['nrfjprog', '--ids'])
@@ -46,7 +47,8 @@
# Translate the op
families = {'NRF51_FAMILY': 'NRF51', 'NRF52_FAMILY': 'NRF52',
- 'NRF53_FAMILY': 'NRF53', 'NRF54L_FAMILY': 'NRF54L', 'NRF91_FAMILY': 'NRF91'}
+ 'NRF53_FAMILY': 'NRF53', 'NRF54L_FAMILY': 'NRF54L',
+ 'NRF54H_FAMILY': 'NRF54H', 'NRF91_FAMILY': 'NRF91'}
cores = {'NRFDL_DEVICE_CORE_APPLICATION': 'CP_APPLICATION',
'NRFDL_DEVICE_CORE_NETWORK': 'CP_NETWORK'}