Skip to content

Commit

Permalink
flash/nor/nrf5: add basic nRF53 and nRF91 support
Browse files Browse the repository at this point in the history
Probes all flash and UICR areas.
Flash erase and write tested.

On nRF53 mass erase works on the application core flash bank only.
The Tcl script nrf53_recover can serve as the workaround on the
network core.
TODO: mass erase of the nRF53 network core flash.

Some ideas taken from [1] and [2].

Change-Id: I8e27a780f4d82bcabf029f79b87ac46cf6a531c7
Link: [1] 7404: flash: nor: add support for Nordic nRF9160 | https://review.openocd.org/c/openocd/+/7404
Link: [2] 8062: flash: nor: add support for Nordic nRF9160 | https://review.openocd.org/c/openocd/+/8062
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: https://review.openocd.org/c/openocd/+/8112
Reviewed-by: Tomáš Beneš <tomas@dronetag.cz>
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
  • Loading branch information
tom-van committed Jun 8, 2024
1 parent fc7a428 commit d94daf7
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 39 deletions.
13 changes: 7 additions & 6 deletions doc/openocd.texi
Original file line number Diff line number Diff line change
Expand Up @@ -7316,12 +7316,13 @@ flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME
@end deffn

@deffn {Flash Driver} {nrf5}
All members of the nRF51 microcontroller families from Nordic Semiconductor
include internal flash and use ARM Cortex-M0 core. nRF52 family powered
by ARM Cortex-M4 or M4F core is supported too. nRF52832 is fully supported
including BPROT flash protection scheme. nRF52833 and nRF52840 devices are
supported with the exception of security extensions (flash access control list
- ACL).
Supports all members of the nRF51, nRF52 and nRF53 microcontroller families from
Nordic Semiconductor. nRF91 family is supported too. One driver handles both
the main flash and the UICR area.

Flash protection is handled on nRF51 family and nRF52805, nRF52810, nRF52811,
nRF52832 devices. Flash access control list (ACL) protection scheme of the newer
devices is not supported.

@example
flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME
Expand Down
207 changes: 174 additions & 33 deletions src/flash/nor/nrf5.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ enum nrf5_features {
NRF5_FEATURE_SERIES_52 = BIT(1),
NRF5_FEATURE_BPROT = BIT(2),
NRF5_FEATURE_ACL_PROT = BIT(3),
NRF5_FEATURE_SERIES_53 = BIT(4),
NRF5_FEATURE_SERIES_91 = BIT(5),
NRF5_FEATURE_ERASE_BY_FLASH_WR = BIT(6),
};

struct nrf5_device_spec {
Expand Down Expand Up @@ -268,6 +271,55 @@ static const struct nrf5_map nrf51_52_map = {
.watchdog_refresh_addr = 0x40010600,
};


/* Third generation devices (nRF53, nRF91) */

static const struct nrf5_ficr_map nrf53_91_ficr_offsets = {
.codepagesize = 0x220,
.codesize = 0x224,
.configid = 0x200,
.info_part = 0x20c,
.info_variant = 0x210,
.info_package = 0x214,
.info_ram = 0x218,
.info_flash = 0x21c,
};

enum {
NRF53APP_91_FICR_BASE = 0x00FF0000,
NRF53APP_91_UICR_BASE = 0x00FF8000,
NRF53NET_FLASH_BASE = 0x01000000,
NRF53NET_FICR_BASE = 0x01FF0000,
NRF53NET_UICR_BASE = 0x01FF8000,
};

static const struct nrf5_map nrf53app_91_map = {
.flash_base = NRF5_FLASH_BASE,
.ficr_base = NRF53APP_91_FICR_BASE,
.uicr_base = NRF53APP_91_UICR_BASE,
.nvmc_base = 0x50039000,

.watchdog_refresh_addr = 0x50018600,
};

/* nRF53 duality:
* SoC consists of two Cortex-M33 cores:
* - application core with security extensions
* - network core
* Each core has its own RAM, flash, FICR and UICR
* The flash driver probes and handles flash and UICR of one core
* independently of those dedicated to the other core.
*/
static const struct nrf5_map nrf53net_map = {
.flash_base = NRF53NET_FLASH_BASE,
.ficr_base = NRF53NET_FICR_BASE,
.uicr_base = NRF53NET_UICR_BASE,
.nvmc_base = 0x41080000,

.watchdog_refresh_addr = 0x41080000,
};


const struct flash_driver nrf5_flash, nrf51_flash;

static bool nrf5_bank_is_probed(const struct flash_bank *bank)
Expand Down Expand Up @@ -595,10 +647,15 @@ static int nrf5_get_chip_type_str(const struct nrf5_info *chip, char *buf, unsig
} else if (chip->ficr_info_valid) {
char variant[5];
nrf5_info_variant_to_str(chip->ficr_info.variant, variant);
res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)",
chip->ficr_info.part,
nrf5_decode_info_package(chip->ficr_info.package),
variant, &variant[2]);
if (chip->features & (NRF5_FEATURE_SERIES_53 | NRF5_FEATURE_SERIES_91)) {
res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s",
chip->ficr_info.part, variant);
} else {
res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)",
chip->ficr_info.part,
nrf5_decode_info_package(chip->ficr_info.package),
variant, &variant[2]);
}
} else {
res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid);
}
Expand Down Expand Up @@ -627,26 +684,27 @@ static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd)
return ERROR_OK;
}

static int nrf5_read_ficr_info(struct nrf5_info *chip, const struct nrf5_map *map,
static int nrf5_read_ficr_info_part(struct nrf5_info *chip, const struct nrf5_map *map,
const struct nrf5_ficr_map *ficr_offsets)
{
int res;
struct target *target = chip->target;
uint32_t ficr_base = map->ficr_base;

chip->ficr_info_valid = false;

res = target_read_u32(target, ficr_base + ficr_offsets->info_part, &chip->ficr_info.part);
if (res != ERROR_OK) {
int res = target_read_u32(target, ficr_base + ficr_offsets->info_part, &chip->ficr_info.part);
if (res != ERROR_OK)
LOG_DEBUG("Couldn't read FICR INFO.PART register");
return res;
}

return res;
}

static int nrf51_52_partno_check(struct nrf5_info *chip)
{

uint32_t series = chip->ficr_info.part & 0xfffff000;
switch (series) {
case 0x51000:
chip->features = NRF5_FEATURE_SERIES_51;
break;
return ERROR_OK;

case 0x52000:
chip->features = NRF5_FEATURE_SERIES_52;
Expand All @@ -665,19 +723,40 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip, const struct nrf5_map *ma
chip->features |= NRF5_FEATURE_ACL_PROT;
break;
}
break;
return ERROR_OK;

default:
LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08"
PRIx32, chip->ficr_info.part);
PRIx32, chip->ficr_info.part);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
}

static int nrf53_91_partno_check(struct nrf5_info *chip)
{
uint32_t series = chip->ficr_info.part & 0xffffff00;
switch (series) {
case 0x5300:
chip->features = NRF5_FEATURE_SERIES_53 | NRF5_FEATURE_ERASE_BY_FLASH_WR;
return ERROR_OK;

/* Now we know the device has FICR INFO filled by something relevant:
* Although it is not documented, the tested nRF51 rev 3 devices
* have FICR INFO.PART, RAM and FLASH of the same format as nRF52.
* VARIANT and PACKAGE coding is unknown for a nRF51 device.
* nRF52 devices have FICR INFO documented and always filled. */
case 0x9100:
chip->features = NRF5_FEATURE_SERIES_91 | NRF5_FEATURE_ERASE_BY_FLASH_WR;
return ERROR_OK;

default:
LOG_DEBUG("Invalid FICR INFO PART value 0x%08"
PRIx32, chip->ficr_info.part);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
}

static int nrf5_read_ficr_more_info(struct nrf5_info *chip)
{
int res;
struct target *target = chip->target;
const struct nrf5_ficr_map *ficr_offsets = chip->ficr_offsets;
uint32_t ficr_base = chip->map->ficr_base;

res = target_read_u32(target, ficr_base + ficr_offsets->info_variant, &chip->ficr_info.variant);
if (res != ERROR_OK)
Expand All @@ -692,11 +771,7 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip, const struct nrf5_map *ma
return res;

res = target_read_u32(target, ficr_base + ficr_offsets->info_flash, &chip->ficr_info.flash);
if (res != ERROR_OK)
return res;

chip->ficr_info_valid = true;
return ERROR_OK;
return res;
}

/* nRF51 series only */
Expand Down Expand Up @@ -735,7 +810,7 @@ static int nrf51_get_ram_size(struct target *target, uint32_t *ram_size)

static int nrf5_probe(struct flash_bank *bank)
{
int res;
int res = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
Expand All @@ -744,15 +819,72 @@ static int nrf5_probe(struct flash_bank *bank)
struct target *target = chip->target;

chip->spec = NULL;
chip->ficr_info_valid = false;

/* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */
chip->features = NRF5_FEATURE_SERIES_51;
chip->map = &nrf51_52_map;
chip->ficr_offsets = &nrf51_52_ficr_offsets;
/* First try to detect nRF53/91 */
switch (bank->base) {
case NRF5_FLASH_BASE:
case NRF53APP_91_UICR_BASE:
res = nrf5_read_ficr_info_part(chip, &nrf53app_91_map, &nrf53_91_ficr_offsets);
if (res != ERROR_OK)
break;

/* Don't bail out on error for the case that some old engineering
* sample has FICR INFO registers unreadable. We can proceed anyway. */
(void)nrf5_read_ficr_info(chip, chip->map, chip->ficr_offsets);
res = nrf53_91_partno_check(chip);
if (res != ERROR_OK)
break;

chip->map = &nrf53app_91_map;
chip->ficr_offsets = &nrf53_91_ficr_offsets;
break;

case NRF53NET_FLASH_BASE:
case NRF53NET_UICR_BASE:
res = nrf5_read_ficr_info_part(chip, &nrf53net_map, &nrf53_91_ficr_offsets);
if (res != ERROR_OK)
break;

res = nrf53_91_partno_check(chip);
if (res != ERROR_OK)
break;

chip->map = &nrf53net_map;
chip->ficr_offsets = &nrf53_91_ficr_offsets;
break;

default:
break;
}

/* If nRF53/91 is not detected, try nRF51/52 */
if (res != ERROR_OK) {
/* Guess a nRF51 series if the device has no FICR INFO and we don't know HWID */
chip->features = NRF5_FEATURE_SERIES_51;
chip->map = &nrf51_52_map;
chip->ficr_offsets = &nrf51_52_ficr_offsets;

/* Don't bail out on error for the case that some old engineering
* sample has FICR INFO registers unreadable. We can proceed anyway. */
res = nrf5_read_ficr_info_part(chip, chip->map, chip->ficr_offsets);
if (res == ERROR_OK)
res = nrf51_52_partno_check(chip);
}

if (res == ERROR_OK) {
/* Now we know the device has FICR INFO filled by something relevant:
* Although it is not documented, the tested nRF51 rev 3 devices
* have FICR INFO.PART, RAM and FLASH of the same format as nRF52.
* VARIANT and PACKAGE coding is unknown for a nRF51 device.
* nRF52 devices have FICR INFO documented and always filled. */
res = nrf5_read_ficr_more_info(chip);
if (res == ERROR_OK) {
chip->ficr_info_valid = true;
} else if (chip->features & NRF5_FEATURE_SERIES_51) {
LOG_DEBUG("Couldn't read some of FICR INFO registers");
} else {
LOG_ERROR("Couldn't read some of FICR INFO registers");
return res;
}
}

const struct nrf5_ficr_map *ficr_offsets = chip->ficr_offsets;
uint32_t ficr_base = chip->map->ficr_base;
Expand Down Expand Up @@ -904,6 +1036,9 @@ static int nrf5_erase_page(struct flash_bank *bank,

res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEUICR, 0x00000001);

} else if (chip->features & NRF5_FEATURE_ERASE_BY_FLASH_WR) {
res = target_write_u32(chip->target, bank->base + sector->offset, 0xffffffff);

} else {
res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEPAGE, sector->offset);
}
Expand Down Expand Up @@ -1175,7 +1310,10 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)

switch (bank->base) {
case NRF5_FLASH_BASE:
case NRF53NET_FLASH_BASE:
case NRF51_52_UICR_BASE:
case NRF53APP_91_UICR_BASE:
case NRF53NET_UICR_BASE:
break;
default:
LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
Expand All @@ -1194,9 +1332,12 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)

switch (bank->base) {
case NRF5_FLASH_BASE:
case NRF53NET_FLASH_BASE:
nbank = &chip->bank[0];
break;
case NRF51_52_UICR_BASE:
case NRF53APP_91_UICR_BASE:
case NRF53NET_UICR_BASE:
nbank = &chip->bank[1];
break;
}
Expand Down

0 comments on commit d94daf7

Please sign in to comment.