west: runners: nrf: Add an option to control the ext erase mode

The erase mode for any external memory that is mapped to the address
space of the MCU is derived from the internal non-volatile memory erase
mode. In order to allow users to override the default value, add a new
--ext-erase-mode command-line option that takes an erase mode just like
--erase-mode does.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2025-04-12 17:48:51 +02:00 committed by Benjamin Cabé
commit 999b6a14a4
3 changed files with 40 additions and 19 deletions

View file

@ -79,8 +79,8 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end base class for nrf tools.''' '''Runner front-end base class for nrf tools.'''
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False, def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
erase_mode=None, reset=True, tool_opt=None, force=False, erase_mode=None, ext_erase_mode=None, reset=True,
recover=False): tool_opt=None, force=False, recover=False):
super().__init__(cfg) super().__init__(cfg)
self.hex_ = cfg.hex_file self.hex_ = cfg.hex_file
# The old --nrf-family options takes upper-case family names # The old --nrf-family options takes upper-case family names
@ -90,6 +90,7 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
self.dev_id = dev_id self.dev_id = dev_id
self.erase = bool(erase) self.erase = bool(erase)
self.erase_mode = erase_mode self.erase_mode = erase_mode
self.ext_erase_mode = ext_erase_mode
self.reset = bool(reset) self.reset = bool(reset)
self.force = force self.force = force
self.recover = bool(recover) self.recover = bool(recover)
@ -140,9 +141,13 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
memory and disable read back protection before memory and disable read back protection before
flashing (erases flash for both cores on nRF53)''') flashing (erases flash for both cores on nRF53)''')
parser.add_argument('--erase-mode', required=False, parser.add_argument('--erase-mode', required=False,
choices=['none', 'ranges', 'all'], dest='erase_mode', choices=['none', 'ranges', 'all'],
help='Select the type of erase operation for the ' help='Select the type of erase operation for the '
'internal non-volatile memory') 'internal non-volatile memory')
parser.add_argument('--ext-erase-mode', required=False,
choices=['none', 'ranges', 'all'],
help='Select the type of erase operation for the '
'external non-volatile memory')
parser.set_defaults(reset=True) parser.set_defaults(reset=True)
@ -439,8 +444,6 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
else: else:
erase_arg = 'ERASE_RANGES_TOUCHED_BY_FIRMWARE' erase_arg = 'ERASE_RANGES_TOUCHED_BY_FIRMWARE'
self.logger.debug(f'Erase type: {erase_arg}')
xip_ranges = { xip_ranges = {
'nrf52': (0x12000000, 0x19FFFFFF), 'nrf52': (0x12000000, 0x19FFFFFF),
'nrf53': (0x10000000, 0x1FFFFFFF), 'nrf53': (0x10000000, 0x1FFFFFFF),
@ -450,8 +453,16 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
xip_start, xip_end = xip_ranges[self.family] xip_start, xip_end = xip_ranges[self.family]
if self.hex_refers_region(xip_start, xip_end): if self.hex_refers_region(xip_start, xip_end):
# Default to pages for the external memory # Default to pages for the external memory
ext_mem_erase_opt = erase_arg if erase_arg == 'ERASE_ALL' else \ ext_mem_erase_opt = self._get_erase_mode(self.ext_erase_mode) or \
'ERASE_RANGES_TOUCHED_BY_FIRMWARE' (erase_arg if erase_arg == 'ERASE_ALL' else \
'ERASE_RANGES_TOUCHED_BY_FIRMWARE')
if not ext_mem_erase_opt and self.ext_erase_mode:
self.logger.warning('Option --ext-erase-mode ignored, no parts of the '
'image refer to external memory')
self.logger.debug(f'Erase modes: chip:{erase_arg} ext_mem:'
f'{ext_mem_erase_opt}')
self.op_program(self.hex_, erase_arg, ext_mem_erase_opt, defer=True, core=core) self.op_program(self.hex_, erase_arg, ext_mem_erase_opt, defer=True, core=core)
self.flush(force=False) self.flush(force=False)
@ -548,6 +559,10 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
raise RuntimeError('Options --erase and --erase-mode are mutually ' raise RuntimeError('Options --erase and --erase-mode are mutually '
'exclusive.') 'exclusive.')
if self.erase and self.ext_erase_mode:
raise RuntimeError('Options --erase and --ext-erase-mode are mutually '
'exclusive.')
self.ensure_family() self.ensure_family()
if self.family != 'nrf54l' and self.erase_mode: if self.family != 'nrf54l' and self.erase_mode:

View file

@ -18,11 +18,12 @@ class NrfJprogBinaryRunner(NrfBinaryRunner):
'''Runner front-end for nrfjprog.''' '''Runner front-end for nrfjprog.'''
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False, def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
erase_mode=None, reset=True, tool_opt=None, force=False, erase_mode=None, ext_erase_mode=None, reset=True, tool_opt=None,
recover=False, qspi_ini=None): force=False, recover=False, qspi_ini=None):
super().__init__(cfg, family, softreset, pinreset, dev_id, erase, super().__init__(cfg, family, softreset, pinreset, dev_id, erase,
erase_mode, reset, tool_opt, force, recover) erase_mode, ext_erase_mode, reset, tool_opt, force,
recover)
self.qspi_ini = qspi_ini self.qspi_ini = qspi_ini
@ -46,9 +47,11 @@ class NrfJprogBinaryRunner(NrfBinaryRunner):
def do_create(cls, cfg, args): def do_create(cls, cfg, args):
return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset, return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset,
args.pinreset, args.dev_id, erase=args.erase, args.pinreset, args.dev_id, erase=args.erase,
erase_mode=args.erase_mode, reset=args.reset, erase_mode=args.erase_mode,
tool_opt=args.tool_opt, force=args.force, ext_erase_mode=args.ext_erase_mode,
recover=args.recover, qspi_ini=args.qspi_ini) reset=args.reset, tool_opt=args.tool_opt,
force=args.force, recover=args.recover,
qspi_ini=args.qspi_ini)
@classmethod @classmethod
def do_add_parser(cls, parser): def do_add_parser(cls, parser):
super().do_add_parser(parser) super().do_add_parser(parser)

View file

@ -17,11 +17,13 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
'''Runner front-end for nrfutil.''' '''Runner front-end for nrfutil.'''
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False, def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
erase_mode=None, reset=True, tool_opt=None, force=False, erase_mode=None, ext_erase_mode=None, reset=True, tool_opt=None,
recover=False, suit_starter=False, ext_mem_config_file=None): force=False, recover=False, suit_starter=False,
ext_mem_config_file=None):
super().__init__(cfg, family, softreset, pinreset, dev_id, erase, super().__init__(cfg, family, softreset, pinreset, dev_id, erase,
erase_mode, reset, tool_opt, force, recover) erase_mode, ext_erase_mode, reset, tool_opt, force,
recover)
self.suit_starter = suit_starter self.suit_starter = suit_starter
self.ext_mem_config_file = ext_mem_config_file self.ext_mem_config_file = ext_mem_config_file
@ -50,9 +52,10 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
def do_create(cls, cfg, args): def do_create(cls, cfg, args):
return NrfUtilBinaryRunner(cfg, args.nrf_family, args.softreset, return NrfUtilBinaryRunner(cfg, args.nrf_family, args.softreset,
args.pinreset, args.dev_id, erase=args.erase, args.pinreset, args.dev_id, erase=args.erase,
erase_mode=args.erase_mode, reset=args.reset, erase_mode=args.erase_mode,
tool_opt=args.tool_opt, force=args.force, ext_erase_mode=args.ext_erase_mode,
recover=args.recover, reset=args.reset, tool_opt=args.tool_opt,
force=args.force, recover=args.recover,
suit_starter=args.suit_manifest_starter, suit_starter=args.suit_manifest_starter,
ext_mem_config_file=args.ext_mem_config_file) ext_mem_config_file=args.ext_mem_config_file)