This is an automated email from Gerrit. "Tomáš Beneš <to...@dronetag.cz>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8063
-- gerrit commit 55152034d490ee4ceb61c3d3715b181ac1eff75b Author: Tomáš Beneš <to...@dronetag.cz> Date: Tue Jan 2 08:42:14 2024 +0100 flash: nor: add support for Nordic nRF9160 Original patch by: Tobias Rohde <t...@lobaro.com> Anton D. Kachalov <mo...@ya.ru> Change-Id: If658526ead175faf726905fda9bcdab34a9fbf22 Signed-off-by: Tomáš Beneš <to...@dronetag.cz> diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index a63b72c8fa..e25b51ddda 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -275,6 +275,8 @@ extern const struct flash_driver msp432_flash; extern const struct flash_driver niietcm4_flash; extern const struct flash_driver npcx_flash; extern const struct flash_driver nrf51_flash; +extern const struct flash_driver nrf52_flash; +extern const struct flash_driver nrf91_flash; extern const struct flash_driver nrf5_flash; extern const struct flash_driver numicro_flash; extern const struct flash_driver ocl_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3157bd3292..bd935a70a6 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -53,6 +53,8 @@ static const struct flash_driver * const flash_drivers[] = { &npcx_flash, &nrf5_flash, &nrf51_flash, + &nrf52_flash, + &nrf91_flash, &numicro_flash, &ocl_flash, &pic32mx_flash, diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index d5de4a4644..117df66667 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -22,9 +22,6 @@ #define WATCHDOG_REFRESH_REGISTER 0x40010600 #define WATCHDOG_REFRESH_VALUE 0x6e524635 -enum { - NRF5_FLASH_BASE = 0x00000000, -}; enum nrf5_ficr_registers { NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ @@ -135,16 +132,121 @@ struct nrf5_device_spec { enum nrf5_features features; }; -struct nrf5_info { - unsigned int refcount; +struct nrfx_target_static_info { + struct { + uint32_t nvmc; + uint32_t ficr; + } peripherals_base; + + struct { + uint32_t flash; + uint32_t uicr; + } flash_base; + + struct { + uint32_t part_reg; + uint32_t code_size_reg; + uint32_t codepage_size_reg; + uint32_t ram_size_reg; + uint32_t flash_size_reg; + uint32_t variant_reg; + uint32_t package_reg; + } ficr_reg_addresses; + + struct { + uint32_t ready_reg; + uint32_t config_reg; + uint32_t erase_page_reg; + uint32_t erase_all_reg; + uint32_t erase_uicr_reg; + } nvmc_reg_addresses; +}; + +#define NRF91_NVMC_BASE 0x50039000 +#define NRF91_FLASH_BASE 0x00000000 +#define NRF91_UICR_BASE 0x00ff8000 +#define NRF91_FICR_BASE 0x00ff0000 + +struct nrfx_target_static_info NRF9_INFO = { + .peripherals_base = { + .nvmc = NRF91_NVMC_BASE, + .ficr = NRF91_FICR_BASE, + }, + .flash_base = { + .flash = NRF91_FLASH_BASE, + .uicr = NRF91_UICR_BASE, + }, + .ficr_reg_addresses = { + .part_reg = 0x140, + .code_size_reg = 0x224, + .codepage_size_reg = 0x220, + .ram_size_reg = 0x218, + .flash_size_reg = 0x21C, + .variant_reg = 0x148, + .package_reg = 0x144, /* Not really package */ + }, + .nvmc_reg_addresses = { + .ready_reg = 0x400, + .erase_all_reg = 0x50C, + .config_reg = 0x504 + } +}; - struct nrf5_bank { - struct nrf5_info *chip; - bool probed; - } bank[2]; +#define NRF5_FLASH_BASE 0x00000000 +#define NRF5_NVMC_BASE 0x4001E000 +#define NRF5_UICR_BASE 0x4001E000 +#define NRF5_FICR_BASE 0x10000000 + +struct nrfx_target_static_info NRF5_INFO = { + .peripherals_base = { + .nvmc = NRF5_NVMC_BASE, + .ficr = NRF5_FICR_BASE, + }, + .flash_base = { + .flash = NRF5_FLASH_BASE, + .uicr = NRF5_FLASH_BASE, + }, + .ficr_reg_addresses = { + .part_reg = 0x060, + .code_size_reg = 0x224, + .codepage_size_reg = 0x220, + .ram_size_reg = 0x10C, + .flash_size_reg = 0x110, + .variant_reg = 0x104, + .package_reg = 0x108, + }, + .nvmc_reg_addresses = { + .ready_reg = 0x400, + .erase_all_reg = 0x50C, + .config_reg = 0x504, + .erase_page_reg = 0x508, + .erase_uicr_reg = 0x514 + } +}; + +struct nrfx_target_static_info *NRFX_INFOS[] = { &NRF9_INFO, &NRF5_INFO }; + +struct nrfx_target_info { + /* Statically defined fields + * Defines addresses of peripherals and registers + * It is set by the probe method to the appropriate nrf series + */ + struct nrfx_target_static_info *stat; + + /* Dynamicly read fields*/ + uint32_t code_page_size; + uint32_t code_size; +}; + +struct nrfx_ctx { + unsigned int refcount; struct target *target; + struct nrfx_target_info info; + + /* Designates whether target has been already probed */ + bool probed; - /* chip identification stored in nrf5_probe() for use in nrf5_info() */ + /* ctx identification stored in nrfx_probe() for use in nrfx_ctx() */ bool ficr_info_valid; struct nrf52_ficr_info ficr_info; const struct nrf5_device_spec *spec; @@ -154,114 +256,26 @@ struct nrf5_info { unsigned int ram_size_kb; }; -#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ -{ \ -.hwid = (id), \ -.part = pt, \ -.variant = var, \ -.build_code = bcode, \ -.flash_size_kb = (fsize), \ -.features = NRF5_FEATURE_SERIES_51, \ +#define IS_NRF5X_SERIES(ctx) ((ctx)->info.stat == &NRF5_INFO) +#define IS_NRF9X_SERIES(ctx) ((ctx)->info.stat == &NRF9_INFO) +#define BANK_IS_UICR(ctx, bank) ((ctx)->info.stat->flash_base.uicr == (bank)->base) +#define NVMC_ERASEPAGE_REG_PRESENT(ctx) ((ctx)->info.stat->nvmc_reg_addresses.erase_page_reg != 0) +#define NVMC_ERASEUICR_REG_PRESENT(ctx) ((ctx)->info.stat->nvmc_reg_addresses.erase_uicr_reg != 0) + +static int nrfx_read_ficr_u32(struct nrfx_ctx *ctx, uint32_t reg_addr, uint32_t *value) +{ + return target_read_u32(ctx->target, ctx->info.stat->peripherals_base.ficr + reg_addr, value); } -#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \ -{ \ -.hwid = (id), \ -.part = pt, \ -.variant = var, \ -.build_code = bcode, \ -.flash_size_kb = (fsize), \ -.features = features, \ +static int nrfx_read_nvmc_u32(struct nrfx_ctx *ctx, uint32_t reg_addr, uint32_t *value) +{ + return target_read_u32(ctx->target, ctx->info.stat->peripherals_base.nvmc + reg_addr, value); } -/* The known devices table below is derived from the "nRF5x series - * compatibility matrix" documents, which can be found in the "DocLib" of - * nordic: - * - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview - * - * Up to date with Matrix v2.0, plus some additional HWIDs. - * - * The additional HWIDs apply where the build code in the matrix is - * shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is - * for x==0, x!=0 means different (unspecified) HWIDs. - */ -static const struct nrf5_device_spec nrf5_known_devices_table[] = { - /* nRF51822 Devices (IC rev 1). */ - NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), - NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), - NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), - NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), - NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), - - /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards - with built-in jlink seem to use engineering samples not listed - in the nRF51 Series Compatibility Matrix V1.0. */ - NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), - - /* nRF51822 Devices (IC rev 2). */ - NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), - NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), - NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), - NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), - NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), - NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), - NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), - NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), - NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), - - /* nRF51822 Devices (IC rev 3). */ - NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), - NRF51_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256), - NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), - NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), - NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), - NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), - NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), - NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), - NRF51_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), - - /* nRF51422 Devices (IC rev 1). */ - NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), - NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), - NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), - - /* nRF51422 Devices (IC rev 2). */ - NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), - NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), - NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), - NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), - - /* nRF51422 Devices (IC rev 3). */ - NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), - NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), - NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), - NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), - NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), - NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), - NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), - - /* The driver fully autodetects nRF52 series devices by FICR INFO, - * no need for nRF52xxx HWIDs in this table */ -#if 0 - /* nRF52810 Devices */ - NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - - /* nRF52832 Devices */ - NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - - /* nRF52840 Devices */ - NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT), -#endif -}; +static int nrfx_write_nvmc_u32(struct nrfx_ctx *ctx, uint32_t reg_addr, uint32_t value) +{ + return target_write_u32(ctx->target, ctx->info.stat->peripherals_base.nvmc + reg_addr, value); +} struct nrf5_device_package { uint32_t package; @@ -279,33 +293,22 @@ static const struct nrf5_device_package nrf5_packages_table[] = { const struct flash_driver nrf5_flash, nrf51_flash; -static bool nrf5_bank_is_probed(const struct flash_bank *bank) -{ - struct nrf5_bank *nbank = bank->driver_priv; - - assert(nbank); - - return nbank->probed; -} -static int nrf5_probe(struct flash_bank *bank); - -static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip) +static int nrfx_probe(struct flash_bank *bank); +static int nrfx_get_probed_ctx_if_halted(struct flash_bank *bank, struct nrfx_ctx **out_ctx) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - struct nrf5_bank *nbank = bank->driver_priv; - *chip = nbank->chip; - - if (nrf5_bank_is_probed(bank)) + struct nrfx_ctx *ctx = bank->driver_priv; + *out_ctx = ctx; + if (ctx->probed) return ERROR_OK; - - return nrf5_probe(bank); + return nrfx_probe(bank); } -static int nrf5_wait_for_nvmc(struct nrf5_info *chip) +static int nrfx_wait_for_nvmc(struct nrfx_ctx *ctx) { uint32_t ready; int res; @@ -313,7 +316,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) int64_t ts_start = timeval_ms(); do { - res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); + res = nrfx_read_nvmc_u32(ctx, ctx->info.stat->nvmc_reg_addresses.ready_reg, &ready); if (res != ERROR_OK) { LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)"); return res; @@ -330,11 +333,12 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) return ERROR_FLASH_BUSY; } -static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) +static int nrfx_nvmc_erase_enable(struct nrfx_ctx *ctx) { int res; - res = target_write_u32(chip->target, - NRF5_NVMC_CONFIG, + + res = nrfx_write_nvmc_u32(ctx, + ctx->info.stat->nvmc_reg_addresses.config_reg, NRF5_NVMC_CONFIG_EEN); if (res != ERROR_OK) { @@ -346,18 +350,18 @@ static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf5_wait_for_nvmc(chip); + res = nrfx_wait_for_nvmc(ctx); if (res != ERROR_OK) LOG_ERROR("Erase enable did not complete"); return res; } -static int nrf5_nvmc_write_enable(struct nrf5_info *chip) +static int nrfx_nvmc_write_enable(struct nrfx_ctx *ctx) { int res; - res = target_write_u32(chip->target, - NRF5_NVMC_CONFIG, + res = nrfx_write_nvmc_u32(ctx, + ctx->info.stat->nvmc_reg_addresses.config_reg, NRF5_NVMC_CONFIG_WEN); if (res != ERROR_OK) { @@ -369,18 +373,18 @@ static int nrf5_nvmc_write_enable(struct nrf5_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf5_wait_for_nvmc(chip); + res = nrfx_wait_for_nvmc(ctx); if (res != ERROR_OK) LOG_ERROR("Write enable did not complete"); return res; } -static int nrf5_nvmc_read_only(struct nrf5_info *chip) +static int nrfx_nvmc_read_only(struct nrfx_ctx *ctx) { int res; - res = target_write_u32(chip->target, - NRF5_NVMC_CONFIG, + res = nrfx_write_nvmc_u32(ctx, + ctx->info.stat->nvmc_reg_addresses.config_reg, NRF5_NVMC_CONFIG_REN); if (res != ERROR_OK) { @@ -391,36 +395,66 @@ static int nrf5_nvmc_read_only(struct nrf5_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf5_wait_for_nvmc(chip); + res = nrfx_wait_for_nvmc(ctx); if (res != ERROR_OK) LOG_ERROR("Read only enable did not complete"); return res; } -static int nrf5_nvmc_generic_erase(struct nrf5_info *chip, +static int nrf9_nvmc_page_erase(struct nrfx_ctx *ctx, + struct flash_sector *sector) +{ + int res; + res = nrfx_nvmc_erase_enable(ctx); + if (res != ERROR_OK) + goto error; + + res = target_write_u32(ctx->target, + sector->offset, + 0xFFFFFFFF); + + if (res != ERROR_OK) + goto set_read_only; + + res = nrfx_wait_for_nvmc(ctx); + if (res != ERROR_OK) + goto set_read_only; + + return nrfx_nvmc_read_only(ctx); + +set_read_only: + nrfx_nvmc_read_only(ctx); +error: + LOG_ERROR("** Failed to erase reg: 0x%08" PRIx32 " val: 0x%08" PRIx32, + sector->offset, 0xFFFFFFFF); + return ERROR_FAIL; +} + +static int nrfx_nvmc_generic_erase(struct nrfx_ctx *ctx, uint32_t erase_register, uint32_t erase_value) { int res; - res = nrf5_nvmc_erase_enable(chip); + res = nrfx_nvmc_erase_enable(ctx); if (res != ERROR_OK) goto error; - res = target_write_u32(chip->target, - erase_register, - erase_value); + res = nrfx_write_nvmc_u32(ctx, + erase_register, + erase_value); + if (res != ERROR_OK) goto set_read_only; - res = nrf5_wait_for_nvmc(chip); + res = nrfx_wait_for_nvmc(ctx); if (res != ERROR_OK) goto set_read_only; - return nrf5_nvmc_read_only(chip); + return nrfx_nvmc_read_only(ctx); set_read_only: - nrf5_nvmc_read_only(chip); + nrfx_nvmc_read_only(ctx); error: LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32, erase_register, erase_value); @@ -431,12 +465,11 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank) { int res; uint32_t clenr0; - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_ctx *ctx = bank->driver_priv; - assert(chip); + assert(ctx); - res = target_read_u32(chip->target, NRF51_FICR_CLENR0, + res = target_read_u32(ctx->target, NRF51_FICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); @@ -444,7 +477,7 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank) } if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(ctx->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -461,10 +494,9 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank) static int nrf5_protect_check_bprot(struct flash_bank *bank) { - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_ctx *ctx = bank->driver_priv; - assert(chip); + assert(ctx); static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 }; uint32_t bprot_reg = 0; @@ -477,7 +509,7 @@ static int nrf5_protect_check_bprot(struct flash_bank *bank) if (n_reg >= ARRAY_SIZE(nrf5_bprot_offsets)) break; - res = target_read_u32(chip->target, NRF5_BPROT_BASE + nrf5_bprot_offsets[n_reg], &bprot_reg); + res = target_read_u32(ctx->target, NRF5_BPROT_BASE + nrf5_bprot_offsets[n_reg], &bprot_reg); if (res != ERROR_OK) return res; } @@ -492,15 +524,14 @@ static int nrf5_protect_check(struct flash_bank *bank) if (bank->base == NRF5_UICR_BASE) return ERROR_OK; - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_ctx *ctx = bank->driver_priv; - assert(chip); + assert(ctx); - if (chip->features & NRF5_FEATURE_BPROT) + if (ctx->features & NRF5_FEATURE_BPROT) return nrf5_protect_check_bprot(bank); - if (chip->features & NRF5_FEATURE_SERIES_51) + if (ctx->features & NRF5_FEATURE_SERIES_51) return nrf5_protect_check_clenr0(bank); LOG_WARNING("Flash protection of this nRF device is not supported"); @@ -512,15 +543,14 @@ static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int fi { int res; uint32_t clenr0, ppfc; - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_ctx *ctx = bank->driver_priv; if (first != 0) { LOG_ERROR("Code region 0 must start at the beginning of the bank"); return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(ctx->target, NRF51_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -532,7 +562,7 @@ static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int fi return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(ctx->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size from UICR"); @@ -540,18 +570,18 @@ static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int fi } if (!set || clenr0 != 0xFFFFFFFF) { - LOG_ERROR("You need to perform chip erase before changing the protection settings"); + LOG_ERROR("You need to perform ctx erase before changing the protection settings"); return ERROR_FAIL; } - res = nrf5_nvmc_write_enable(chip); + res = nrfx_nvmc_write_enable(ctx); if (res != ERROR_OK) goto error; clenr0 = bank->sectors[last].offset + bank->sectors[last].size; - res = target_write_u32(chip->target, NRF51_UICR_CLENR0, clenr0); + res = target_write_u32(ctx->target, NRF51_UICR_CLENR0, clenr0); - int res2 = nrf5_wait_for_nvmc(chip); + int res2 = nrfx_wait_for_nvmc(ctx); if (res == ERROR_OK) res = res2; @@ -562,7 +592,7 @@ static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int fi LOG_ERROR("Couldn't write code region 0 size to UICR"); error: - nrf5_nvmc_read_only(chip); + nrfx_nvmc_read_only(ctx); return res; } @@ -571,26 +601,26 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; - struct nrf5_info *chip; + struct nrfx_ctx *ctx = bank->driver_priv; /* UICR cannot be write protected so just bail out early */ - if (bank->base == NRF5_UICR_BASE) { + if (BANK_IS_UICR(ctx, bank)) { LOG_ERROR("UICR page does not support protection"); return ERROR_FLASH_OPER_UNSUPPORTED; } - res = nrf5_get_probed_chip_if_halted(bank, &chip); + res = nrfx_get_probed_ctx_if_halted(bank, &ctx); if (res != ERROR_OK) return res; - if (chip->features & NRF5_FEATURE_SERIES_51) + if (ctx->features & NRF5_FEATURE_SERIES_51) return nrf5_protect_clenr0(bank, set, first, last); - LOG_ERROR("Flash protection setting is not supported on this nRF5 device"); + LOG_ERROR("Flash protection setting is not supported on this nRF device"); return ERROR_FLASH_OPER_UNSUPPORTED; } -static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) +static bool nrfx_ctx_variant_to_str(uint32_t variant, char *bf) { uint8_t b[4]; @@ -614,21 +644,21 @@ static const char *nrf5_decode_info_package(uint32_t package) return "xx"; } -static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size) +static int get_nrf5_ctx_type_str(const struct nrfx_ctx *ctx, char *buf, unsigned int buf_size) { int res; - if (chip->spec) { + if (ctx->spec) { res = snprintf(buf, buf_size, "nRF%s-%s(build code: %s)", - chip->spec->part, chip->spec->variant, chip->spec->build_code); - } else if (chip->ficr_info_valid) { + ctx->spec->part, ctx->spec->variant, ctx->spec->build_code); + } else if (ctx->ficr_info_valid) { char variant[5]; - nrf5_info_variant_to_str(chip->ficr_info.variant, variant); + nrfx_ctx_variant_to_str(ctx->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), + ctx->ficr_info.part, + nrf5_decode_info_package(ctx->ficr_info.package), variant, &variant[2]); } else { - res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid); + res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", ctx->hwid); } /* safety: */ @@ -639,83 +669,97 @@ static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsig return ERROR_OK; } -static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) +static int nrfx_info(struct flash_bank *bank, struct command_invocation *cmd) { - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_ctx *ctx = bank->driver_priv; + LOG_INFO("Info bank 0x%08lx", bank->base); - char chip_type_str[256]; - if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + char ctx_type_str[256]; + if (get_nrf5_ctx_type_str(ctx, ctx_type_str, sizeof(ctx_type_str)) != ERROR_OK) return ERROR_FAIL; command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM", - chip_type_str, chip->flash_size_kb, chip->ram_size_kb); + ctx_type_str, ctx->flash_size_kb, ctx->ram_size_kb); return ERROR_OK; } -static int nrf5_read_ficr_info(struct nrf5_info *chip) +static int nrfx_read_ficr_part_info(struct nrfx_ctx *ctx) { int res; - struct target *target = chip->target; - chip->ficr_info_valid = false; + ctx->ficr_info_valid = false; + struct nrfx_target_static_info *st_info = ctx->info.stat; - res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part); + res = nrfx_read_ficr_u32(ctx, st_info->ficr_reg_addresses.part_reg, &ctx->ficr_info.part); if (res != ERROR_OK) { LOG_DEBUG("Couldn't read FICR INFO.PART register"); return res; } - uint32_t series = chip->ficr_info.part & 0xfffff000; + uint32_t series = ctx->ficr_info.part & 0xfffff000; switch (series) { case 0x51000: - chip->features = NRF5_FEATURE_SERIES_51; + ctx->features = NRF5_FEATURE_SERIES_51; break; case 0x52000: - chip->features = NRF5_FEATURE_SERIES_52; + ctx->features = NRF5_FEATURE_SERIES_52; - switch (chip->ficr_info.part) { + switch (ctx->ficr_info.part) { case 0x52810: case 0x52832: - chip->features |= NRF5_FEATURE_BPROT; + ctx->features |= NRF5_FEATURE_BPROT; break; case 0x52840: - chip->features |= NRF5_FEATURE_ACL_PROT; + ctx->features |= NRF5_FEATURE_ACL_PROT; + break; + } + break; + case 0x9000: + switch (ctx->ficr_info.part) { + case 0x9120: + case 0x9160: break; } break; - default: LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08" - PRIx32, chip->ficr_info.part); + PRIx32, ctx->ficr_info.part); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + return ERROR_OK; +} + +static int nrfx_read_ficr_info(struct nrfx_ctx *ctx) +{ + int res; + ctx->ficr_info_valid = false; + struct nrfx_target_static_info *st_info = ctx->info.stat; /* 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 = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant); + res = nrfx_read_ficr_u32(ctx, st_info->ficr_reg_addresses.variant_reg, &ctx->ficr_info.variant); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package); + res = nrfx_read_ficr_u32(ctx, st_info->ficr_reg_addresses.package_reg, &ctx->ficr_info.package); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram); + res = nrfx_read_ficr_u32(ctx, st_info->ficr_reg_addresses.ram_size_reg, &ctx->ficr_info.ram); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash); + res = nrfx_read_ficr_u32(ctx, st_info->ficr_reg_addresses.flash_size_reg, &ctx->ficr_info.flash); if (res != ERROR_OK) return res; - chip->ficr_info_valid = true; + ctx->ficr_info_valid = true; return ERROR_OK; } @@ -752,94 +796,125 @@ static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) return res; } -static int nrf5_probe(struct flash_bank *bank) +static int nrfx_probe(struct flash_bank *bank) { int res; - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; - struct target *target = chip->target; + struct nrfx_ctx *ctx = bank->driver_priv; + struct target *target = ctx->target; - uint32_t configid; - res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read CONFIGID register"); - return res; - } - - /* HWID is stored in the lower two bytes of the CONFIGID register */ - chip->hwid = configid & 0xFFFF; + struct nrfx_target_static_info *probe_info = NULL; + LOG_INFO("Probing flash bank 0x%08lx", bank->base); + /* Iterate though all register options to determine the family of the device */ + for (size_t i = 0; i < ARRAY_SIZE(NRFX_INFOS); i++) { + struct nrfx_target_static_info *info = NRFX_INFOS[i]; - /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ - chip->features = NRF5_FEATURE_SERIES_51; + uint32_t probe_reg = 0; - /* 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); + /* Cannot use nrfx_read_ficr_u32 ctx->info not set yet */ + res = target_read_u32(ctx->target, info->peripherals_base.ficr + info->ficr_reg_addresses.part_reg, &probe_reg); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read CONFIGID register"); + return res; + } - chip->spec = NULL; - for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { - if (chip->hwid == nrf5_known_devices_table[i].hwid) { - chip->spec = &nrf5_known_devices_table[i]; - chip->features = chip->spec->features; + if (probe_reg != 0) { + probe_info = info; break; } } - if (chip->spec && chip->ficr_info_valid) { - /* check if HWID table gives the same part as FICR INFO */ - if (chip->ficr_info.part != strtoul(chip->spec->part, NULL, 16)) - LOG_WARNING("HWID 0x%04" PRIx32 " mismatch: FICR INFO.PART %" - PRIx32, chip->hwid, chip->ficr_info.part); + if (!probe_info) { + LOG_ERROR("Couldn't detect target"); + return ERROR_FAIL; } + /* Set correct info for reading of information */ + ctx->info.stat = probe_info; + + /* Try to read the FICR CONFIG ID only for nrf51/nrf52 devices */ + if (IS_NRF5X_SERIES(ctx)) { + res = nrfx_read_ficr_part_info(ctx); + if (res == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* Try guessing the nrf51 series with hwid */ + uint32_t configid; + res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read CONFIGID register"); + return res; + } - if (chip->ficr_info_valid) { - chip->ram_size_kb = chip->ficr_info.ram; + /* HWID is stored in the lower two bytes of the CONFIGID register */ + ctx->hwid = configid & 0xFFFF; + + /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ + ctx->features = NRF5_FEATURE_SERIES_51; + } + /* Don't bail out on error for the case that some old engineering + * sample has FICR INFO registers unreadable. We can proceed anyway. */ + (void)nrfx_read_ficr_info(ctx); + } else { + /* For nrf91 series ficr and part info must be known*/ + res = nrfx_read_ficr_part_info(ctx); + if (res != ERROR_OK) { + LOG_ERROR("Unsupported part information"); + return res; + } + + res = nrfx_read_ficr_info(ctx); + if (res != ERROR_OK) { + LOG_ERROR("Failed to retrieve ficr information from the device"); + return res; + } + } + + + if (ctx->ficr_info_valid) { + ctx->ram_size_kb = ctx->ficr_info.ram; } else { uint32_t ram_size; nrf5_get_ram_size(target, &ram_size); - chip->ram_size_kb = ram_size / 1024; + ctx->ram_size_kb = ram_size / 1024; } - /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ - uint32_t flash_page_size; - res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, - &flash_page_size); + + /* The value stored in FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + res = nrfx_read_ficr_u32(ctx, probe_info->ficr_reg_addresses.codepage_size_reg, &ctx->info.code_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); return res; } + uint32_t flash_page_size = ctx->info.code_page_size; /* Note the register name is misleading, - * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ - uint32_t num_sectors; - res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors); + * FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ + res = nrfx_read_ficr_u32(ctx, probe_info->ficr_reg_addresses.code_size_reg, &ctx->info.code_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; } + uint32_t num_sectors = ctx->info.code_size; - chip->flash_size_kb = num_sectors * flash_page_size / 1024; + ctx->flash_size_kb = num_sectors * flash_page_size / 1024; - if (!chip->bank[0].probed && !chip->bank[1].probed) { - char chip_type_str[256]; - if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + if (!ctx->probed) { + char ctx_type_str[256]; + if (get_nrf5_ctx_type_str(ctx, ctx_type_str, sizeof(ctx_type_str)) != ERROR_OK) return ERROR_FAIL; - const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); + const bool device_is_unknown = (!ctx->spec && !ctx->ficr_info_valid); LOG_INFO("%s%s %ukB Flash, %ukB RAM", device_is_unknown ? "Unknown device: " : "", - chip_type_str, - chip->flash_size_kb, - chip->ram_size_kb); + ctx_type_str, + ctx->flash_size_kb, + ctx->ram_size_kb); } free(bank->sectors); - if (bank->base == NRF5_FLASH_BASE) { + if (bank->base == probe_info->flash_base.flash) { /* Sanity check */ - if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb) - LOG_WARNING("Chip's reported Flash capacity does not match expected one"); - if (chip->ficr_info_valid && chip->flash_size_kb != chip->ficr_info.flash) - LOG_WARNING("Chip's reported Flash capacity does not match FICR INFO.FLASH"); + if (ctx->spec && ctx->flash_size_kb != ctx->spec->flash_size_kb) + LOG_WARNING("ctx's reported Flash capacity does not match expected one"); + if (ctx->ficr_info_valid && ctx->flash_size_kb != ctx->ficr_info.flash) + LOG_WARNING("ctx's reported Flash capacity does not match FICR INFO.FLASH"); bank->num_sectors = num_sectors; bank->size = num_sectors * flash_page_size; @@ -847,10 +922,7 @@ static int nrf5_probe(struct flash_bank *bank) bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); if (!bank->sectors) return ERROR_FAIL; - - chip->bank[0].probed = true; - - } else { + } else if (bank->base == probe_info->flash_base.uicr) { bank->num_sectors = 1; bank->size = flash_page_size; @@ -859,41 +931,45 @@ static int nrf5_probe(struct flash_bank *bank) return ERROR_FAIL; bank->sectors[0].is_protected = 0; - - chip->bank[1].probed = true; + } else { + LOG_ERROR("Flash bank with base: 0x%08lx is unsupported", bank->base); + return ERROR_FLASH_BANK_INVALID; } + ctx->probed = true; return ERROR_OK; } -static int nrf5_auto_probe(struct flash_bank *bank) +static int nrfx_auto_probe(struct flash_bank *bank) { - if (nrf5_bank_is_probed(bank)) + struct nrfx_ctx *ctx = bank->driver_priv; + LOG_INFO("Auto-Probing flash bank 0x%08lx", bank->base); + assert(ctx); + if (ctx->probed) return ERROR_OK; - - return nrf5_probe(bank); + return nrfx_probe(bank); } -static int nrf5_erase_all(struct nrf5_info *chip) +static int nrfx_erase_all(struct nrfx_ctx *ctx) { - LOG_DEBUG("Erasing all non-volatile memory"); - return nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEALL, + LOG_INFO("Erasing all non-volatile memory"); + return nrfx_nvmc_generic_erase(ctx, + ctx->info.stat->nvmc_reg_addresses.erase_all_reg, 0x00000001); } -static int nrf5_erase_page(struct flash_bank *bank, - struct nrf5_info *chip, +static int nrfx_erase_page(struct flash_bank *bank, + struct nrfx_ctx *ctx, struct flash_sector *sector) { int res; - LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset); + LOG_INFO("Erasing page at 0x%" PRIx32, sector->offset); - if (bank->base == NRF5_UICR_BASE) { - if (chip->features & NRF5_FEATURE_SERIES_51) { + if (BANK_IS_UICR(ctx, bank)) { + if (ctx->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(ctx->target, NRF51_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -907,29 +983,44 @@ static int nrf5_erase_page(struct flash_bank *bank, if (sector->is_erased == 1) return ERROR_OK; - LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region"); + LOG_ERROR("The ctx was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region"); return ERROR_FAIL; } } - res = nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEUICR, + /* Might be redundant check but better safe than sorry */ + if (IS_NRF5X_SERIES(ctx) && NVMC_ERASEUICR_REG_PRESENT(ctx)) { + res = nrfx_nvmc_generic_erase(ctx, + ctx->info.stat->nvmc_reg_addresses.erase_uicr_reg, 0x00000001); - - + } else if (IS_NRF9X_SERIES(ctx)) { + /* UICR on nRF91 series needs to perform erase-all*/ + res = nrfx_nvmc_generic_erase(ctx, + ctx->info.stat->nvmc_reg_addresses.erase_all_reg, + 0x00000001); + } else { + res = ERROR_FLASH_OPER_UNSUPPORTED; + } } else { - res = nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEPAGE, + /* Might be redundant check but better safe than sorry */ + if (IS_NRF5X_SERIES(ctx) && NVMC_ERASEPAGE_REG_PRESENT(ctx)) { + res = nrfx_nvmc_generic_erase(ctx, + ctx->info.stat->nvmc_reg_addresses.erase_page_reg, sector->offset); + } else if (IS_NRF9X_SERIES(ctx)) { + res = nrf9_nvmc_page_erase(ctx, sector); + } else { + res = ERROR_FLASH_OPER_UNSUPPORTED; + } } return res; } /* Start a low level flash write for the specified region */ -static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes) +static int nrf5_ll_flash_write(struct nrfx_ctx *ctx, uint32_t address, const uint8_t *buffer, uint32_t bytes) { - struct target *target = chip->target; + struct target *target = ctx->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; @@ -954,7 +1045,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u if (retval != ERROR_OK) return retval; - retval = nrf5_wait_for_nvmc(chip); + retval = nrfx_wait_for_nvmc(ctx); if (retval != ERROR_OK) return retval; @@ -1021,12 +1112,14 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u return retval; } -static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, +static int nrfx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - struct nrf5_info *chip; + struct nrfx_ctx *ctx; + LOG_INFO("Writing at 0x%08lx 0x%x bytes", bank->base + offset, count); + - int res = nrf5_get_probed_chip_if_halted(bank, &chip); + int res = nrfx_get_probed_ctx_if_halted(bank, &ctx); if (res != ERROR_OK) return res; @@ -1041,7 +1134,7 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, * * Update protection state and check if any flash sector to be written * is protected. */ - if (chip->features & NRF5_FEATURE_SERIES_51) { + if (ctx->features & NRF5_FEATURE_SERIES_51) { res = nrf5_protect_check_clenr0(bank); if (res != ERROR_OK) @@ -1060,30 +1153,40 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, } } } - - res = nrf5_nvmc_write_enable(chip); + res = nrfx_nvmc_write_enable(ctx); if (res != ERROR_OK) goto error; - res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count); - if (res != ERROR_OK) + if (IS_NRF5X_SERIES(ctx)) { + res = nrf5_ll_flash_write(ctx, bank->base + offset, buffer, count); + if (res != ERROR_OK) + goto error; + } else if (IS_NRF9X_SERIES(ctx)) { + res = target_write_buffer(ctx->target, bank->base + offset, count, buffer); + if (res != ERROR_OK) + goto error; + } else { + res = ERROR_FLASH_OPER_UNSUPPORTED; goto error; + } - return nrf5_nvmc_read_only(chip); + return nrfx_nvmc_read_only(ctx); error: - nrf5_nvmc_read_only(chip); + nrfx_nvmc_read_only(ctx); LOG_ERROR("Failed to write to nrf5 flash"); return res; } -static int nrf5_erase(struct flash_bank *bank, unsigned int first, +static int nrfx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int res; - struct nrf5_info *chip; + struct nrfx_ctx *ctx; - res = nrf5_get_probed_chip_if_halted(bank, &chip); + LOG_INFO("Erase Bank 0x%08lx", bank->base); + + res = nrfx_get_probed_ctx_if_halted(bank, &ctx); if (res != ERROR_OK) return res; @@ -1093,7 +1196,7 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, * * Update protection state and check if any flash sector to be erased * is protected. */ - if (chip->features & NRF5_FEATURE_SERIES_51) { + if (ctx->features & NRF5_FEATURE_SERIES_51) { res = nrf5_protect_check_clenr0(bank); if (res != ERROR_OK) @@ -1102,14 +1205,13 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, /* For each sector to be erased */ for (unsigned int s = first; s <= last && res == ERROR_OK; s++) { - - if (chip->features & NRF5_FEATURE_SERIES_51 + if (ctx->features & NRF5_FEATURE_SERIES_51 && bank->sectors[s].is_protected == 1) { LOG_ERROR("Flash sector %d is protected", s); return ERROR_FLASH_PROTECTED; } - res = nrf5_erase_page(bank, chip, &bank->sectors[s]); + res = nrfx_erase_page(bank, ctx, &bank->sectors[s]); if (res != ERROR_OK) { LOG_ERROR("Error erasing sector %d", s); return res; @@ -1119,25 +1221,24 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, return ERROR_OK; } -static void nrf5_free_driver_priv(struct flash_bank *bank) +static void nrfx_free_driver_priv(struct flash_bank *bank) { - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; - if (!chip) + struct nrfx_ctx *ctx = bank->driver_priv; + if (!ctx) return; - chip->refcount--; - if (chip->refcount == 0) { - free(chip); + ctx->refcount--; + if (ctx->refcount == 0) { + free(ctx); bank->driver_priv = NULL; } } -static struct nrf5_info *nrf5_get_chip(struct target *target) +static struct nrfx_ctx *nrfx_get_target_ctx(struct target *target) { struct flash_bank *bank_iter; - /* iterate over nrf5 banks of same target */ + /* iterate over nrfx banks of same target */ for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { if (bank_iter->driver != &nrf5_flash && bank_iter->driver != &nrf51_flash) continue; @@ -1145,60 +1246,50 @@ static struct nrf5_info *nrf5_get_chip(struct target *target) if (bank_iter->target != target) continue; - struct nrf5_bank *nbank = bank_iter->driver_priv; - if (!nbank) + struct nrfx_ctx *ctx = bank_iter->driver_priv; + if (!ctx) continue; - - if (nbank->chip) - return nbank->chip; + return ctx; } return NULL; } -FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) +FLASH_BANK_COMMAND_HANDLER(nrfx_flash_bank_command) { - struct nrf5_info *chip; - struct nrf5_bank *nbank = NULL; - - switch (bank->base) { - case NRF5_FLASH_BASE: - case NRF5_UICR_BASE: - break; - default: + struct nrfx_ctx *ctx; + + LOG_INFO("Bank cmd bank 0x%08lx", bank->base); + bool valid_base = false; + for (size_t i = 0; i < ARRAY_SIZE(NRFX_INFOS); i++) { + struct nrfx_target_static_info *info = NRFX_INFOS[i]; + if (bank->base == info->flash_base.flash || + bank->base == info->flash_base.uicr) { + valid_base = true; + break; + } + } + if (!valid_base) { LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); return ERROR_FAIL; } - chip = nrf5_get_chip(bank->target); - if (!chip) { - /* Create a new chip */ - chip = calloc(1, sizeof(*chip)); - if (!chip) + ctx = nrfx_get_target_ctx(bank->target); + if (!ctx) { + /* Create a new ctx */ + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) return ERROR_FAIL; - chip->target = bank->target; + ctx->target = bank->target; } - switch (bank->base) { - case NRF5_FLASH_BASE: - nbank = &chip->bank[0]; - break; - case NRF5_UICR_BASE: - nbank = &chip->bank[1]; - break; - } - assert(nbank); - - chip->refcount++; - nbank->chip = chip; - nbank->probed = false; - bank->driver_priv = nbank; + ctx->refcount++; + bank->driver_priv = ctx; bank->write_start_alignment = bank->write_end_alignment = 4; - return ERROR_OK; } -COMMAND_HANDLER(nrf5_handle_mass_erase_command) +COMMAND_HANDLER(nrfx_handle_mass_erase_command) { int res; struct flash_bank *bank = NULL; @@ -1210,13 +1301,13 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) assert(bank); - struct nrf5_info *chip; + struct nrfx_ctx *ctx = bank->driver_priv; - res = nrf5_get_probed_chip_if_halted(bank, &chip); + res = nrfx_get_probed_ctx_if_halted(bank, &ctx); if (res != ERROR_OK) return res; - if (chip->features & NRF5_FEATURE_SERIES_51) { + if (ctx->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; res = target_read_u32(target, NRF51_FICR_PPFC, &ppfc); @@ -1232,14 +1323,14 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) } } - res = nrf5_erase_all(chip); + res = nrfx_erase_all(ctx); if (res == ERROR_OK) { LOG_INFO("Mass erase completed."); - if (chip->features & NRF5_FEATURE_SERIES_51) + if (ctx->features & NRF5_FEATURE_SERIES_51) LOG_INFO("A reset or power cycle is required if the flash was protected before."); } else { - LOG_ERROR("Failed to erase the chip"); + LOG_ERROR("Failed to erase the ctx"); } return res; @@ -1257,9 +1348,9 @@ COMMAND_HANDLER(nrf5_handle_info_command) assert(bank); - struct nrf5_info *chip; + struct nrfx_ctx *ctx; - res = nrf5_get_probed_chip_if_halted(bank, &chip); + res = nrfx_get_probed_ctx_if_halted(bank, &ctx); if (res != ERROR_OK) return res; @@ -1309,7 +1400,7 @@ COMMAND_HANDLER(nrf5_handle_info_command) }; for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { - res = target_read_u32(chip->target, ficr[i].address, + res = target_read_u32(ctx->target, ficr[i].address, &ficr[i].value); if (res != ERROR_OK) { LOG_ERROR("Couldn't read %" PRIx32, ficr[i].address); @@ -1318,7 +1409,7 @@ COMMAND_HANDLER(nrf5_handle_info_command) } for (size_t i = 0; i < ARRAY_SIZE(uicr); i++) { - res = target_read_u32(chip->target, uicr[i].address, + res = target_read_u32(ctx->target, uicr[i].address, &uicr[i].value); if (res != ERROR_OK) { LOG_ERROR("Couldn't read %" PRIx32, uicr[i].address); @@ -1380,9 +1471,9 @@ COMMAND_HANDLER(nrf5_handle_info_command) static const struct command_registration nrf5_exec_command_handlers[] = { { .name = "mass_erase", - .handler = nrf5_handle_mass_erase_command, + .handler = nrfx_handle_mass_erase_command, .mode = COMMAND_EXEC, - .help = "Erase all flash contents of the chip.", + .help = "Erase all flash contents of the ctx.", .usage = "", }, { @@ -1395,7 +1486,18 @@ static const struct command_registration nrf5_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const struct command_registration nrf5_command_handlers[] = { +static const struct command_registration nrfx_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = nrfx_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .help = "Erase all flash contents of the ctx.", + .usage = "Just work", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration nrfx_command_handlers[] = { { .name = "nrf5", .mode = COMMAND_ANY, @@ -1410,39 +1512,76 @@ static const struct command_registration nrf5_command_handlers[] = { .usage = "", .chain = nrf5_exec_command_handlers, }, + { + .name = "nrf52", + .mode = COMMAND_ANY, + .help = "nrf52 flash command group", + .usage = "", + .chain = nrf5_exec_command_handlers, + }, COMMAND_REGISTRATION_DONE }; const struct flash_driver nrf5_flash = { .name = "nrf5", - .commands = nrf5_command_handlers, - .flash_bank_command = nrf5_flash_bank_command, - .info = nrf5_info, - .erase = nrf5_erase, + .commands = nrfx_command_handlers, + .flash_bank_command = nrfx_flash_bank_command, + .info = nrfx_info, + .erase = nrfx_erase, + .protect = nrf5_protect, + .write = nrfx_write, + .read = default_flash_read, + .probe = nrfx_probe, + .auto_probe = nrfx_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = nrf5_protect_check, + .free_driver_priv = nrfx_free_driver_priv, +}; + +const struct flash_driver nrf52_flash = { + .name = "nrf52", + .commands = nrfx_command_handlers, + .flash_bank_command = nrfx_flash_bank_command, + .info = nrfx_info, + .erase = nrfx_erase, .protect = nrf5_protect, - .write = nrf5_write, + .write = nrfx_write, .read = default_flash_read, - .probe = nrf5_probe, - .auto_probe = nrf5_auto_probe, + .probe = nrfx_probe, + .auto_probe = nrfx_auto_probe, .erase_check = default_flash_blank_check, .protect_check = nrf5_protect_check, - .free_driver_priv = nrf5_free_driver_priv, + .free_driver_priv = nrfx_free_driver_priv, +}; + +const struct flash_driver nrf91_flash = { + .name = "nrf91", + .commands = nrfx_exec_command_handlers, + .flash_bank_command = nrfx_flash_bank_command, + .info = nrfx_info, + .erase = nrfx_erase, + .write = nrfx_write, + .read = default_flash_read, + .probe = nrfx_probe, + .auto_probe = nrfx_auto_probe, + .erase_check = default_flash_blank_check, + .free_driver_priv = nrfx_free_driver_priv, }; /* We need to retain the flash-driver name as well as the commands * for backwards compatibility */ const struct flash_driver nrf51_flash = { .name = "nrf51", - .commands = nrf5_command_handlers, - .flash_bank_command = nrf5_flash_bank_command, - .info = nrf5_info, - .erase = nrf5_erase, + .commands = nrfx_command_handlers, + .flash_bank_command = nrfx_flash_bank_command, + .info = nrfx_info, + .erase = nrfx_erase, .protect = nrf5_protect, - .write = nrf5_write, + .write = nrfx_write, .read = default_flash_read, - .probe = nrf5_probe, - .auto_probe = nrf5_auto_probe, + .probe = nrfx_probe, + .auto_probe = nrfx_auto_probe, .erase_check = default_flash_blank_check, .protect_check = nrf5_protect_check, - .free_driver_priv = nrf5_free_driver_priv, + .free_driver_priv = nrfx_free_driver_priv, }; diff --git a/tcl/target/nrf91.cfg b/tcl/target/nrf91.cfg new file mode 100644 index 0000000000..b70f6e5121 --- /dev/null +++ b/tcl/target/nrf91.cfg @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic nRF9160 series: ARM Cortex-M33 +# +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME nrf9160 +} + +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x6ba02477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +adapter speed 1000 + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +if { [using_hla] } { + echo "" + echo "nRF91 device has a CTRL-AP dedicated to recover the device from AP lock." + echo "A high level adapter (like a ST-Link) you are currently using cannot access" + echo "the CTRL-AP so 'nrf91_recover' command will not work." + echo "Do not enable UICR APPROTECT." + echo "" +} else { + cortex_m reset_config sysresetreq + + $_TARGETNAME configure -event examine-fail nrf91_check_ap_lock +} + +flash bank $_CHIPNAME.flash nrf91 0x00000000 0 1 1 $_TARGETNAME +flash bank $_CHIPNAME.uicr nrf91 0xff8000 0 1 1 $_TARGETNAME + + +# Test if MEM-AP is locked by UICR APPROTECT +proc nrf91_check_ap_lock {} { + set dap [[target current] cget -dap] + set err [catch {set APPROTECTSTATUS [$dap apreg 1 0xc]}] + if {$err == 0 && $APPROTECTSTATUS != 1} { + echo "****** WARNING ******" + echo "nRF91 device has AP lock engaged (see UICR APPROTECT register)." + echo "Debug access is denied." + echo "" + poll off + } +} + +source [find target/nrf91_mfw.cfg] \ No newline at end of file diff --git a/tcl/target/nrf91_mfw.cfg b/tcl/target/nrf91_mfw.cfg new file mode 100644 index 0000000000..dc6e32f71d --- /dev/null +++ b/tcl/target/nrf91_mfw.cfg @@ -0,0 +1,430 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Nordic nRF9160 Modem firmware series: ARM Cortex-M33 +# +# Requires python, installed package: 'pip install intelhex' +# Usage: +# -c 'source [find target/nrf91.cfg]' -c 'adapter speed 10000' '-c init' '-c targets' -c 'reset init' -c 'nrf91_flash_modem mfw_nrf9160_1.3.4.zip' -c 'reset run' -c shutdown +# + +set MODEM_FIRMWARE_UPDATE_DEBUG 0 +set MODEM_FIRMWARE_UPDATE_RW_DEBUG 1 + +set EVENT_NONE 0 +set EVENT_FAULT 1 +set EVENT_COMMAND 2 +set EVENT_DATA 3 + +set FAULT_EVENT_REG 0x4002A100 +set COMMAND_EVENT_REG 0x4002A108 +set DATA_EVENT_REG 0x4002A110 + +proc nrf91_mfw_read_memory {address width count} { + if {$::MODEM_FIRMWARE_UPDATE_RW_DEBUG} { + puts -nonewline [format "Read(0x%x) = " $address $count] + } + set RES [read_memory $address $width $count] + if {$::MODEM_FIRMWARE_UPDATE_RW_DEBUG} { + puts $RES + } + return $RES +} + +proc nrf91_mfw_write_memory {address val} { + if {$::MODEM_FIRMWARE_UPDATE_RW_DEBUG} { + puts [format "Write(0x%x, 0x%x)" $address $val] + } + write_memory $address 32 $val +} + +proc nrf91_clear_modem_ctrl_events {} { + nrf91_mfw_write_memory $::FAULT_EVENT_REG 0x0 + nrf91_mfw_write_memory $::COMMAND_EVENT_REG 0x0 + nrf91_mfw_write_memory $::DATA_EVENT_REG 0x0 +} + +proc nrf91_poll_modem_ctrl_event {} { + set RES [nrf91_mfw_read_memory $::FAULT_EVENT_REG 32 1] + if {$RES == 1} { + puts "Fault event received" + set res [nrf91_mfw_read_memory 0x2000000C 32 1] + if {[string match "0x5a*" $res]} { + puts [format "Command Error: 0x%x" $res] + return $::EVENT_FAULT + } + + nrf91_mfw_write_memory $::FAULT_EVENT_REG 0x0 + return $::EVENT_FAULT + } + set RES [nrf91_mfw_read_memory $::COMMAND_EVENT_REG 32 1] + if {$RES == 1} { + set res [nrf91_mfw_read_memory 0x2000000C 32 1] + if {[string match "0x5a*" $res]} { + puts [format "Command Error: 0x%x" $res] + return $::EVENT_FAULT + } + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts [format "Command Result: 0x%x" $res] + } + + nrf91_mfw_write_memory $::COMMAND_EVENT_REG 0x0 + return $::EVENT_COMMAND + } + set RES [nrf91_mfw_read_memory $::DATA_EVENT_REG 32 1] + if {$RES == 1} { + set res [nrf91_mfw_read_memory 0x2000000C 32 1] + nrf91_mfw_write_memory $::DATA_EVENT_REG 0x0 + return $::EVENT_DATA + } + return $::EVENT_NONE +} + +proc nrf91_wait_for_modem_event {} { + set EVT $::EVENT_FAULT + while {1} { + set EVT [nrf91_poll_modem_ctrl_event] + if {$EVT != $::EVENT_NONE} { + break + } + } + return $EVT +} + +proc nrf91_read_memory_padded {address size} { + set readStr [nrf91_mfw_read_memory $address 32 $size] + set wordList [regexp -inline -all -- {\S+} $readStr] + set output {} + foreach w $wordList { + set hex [scan $w %x] + lappend output [format "0x%08x" $hex] + } + return [join $output " "] +} + +proc nrf91_modem_digest_read_prefix {} { + set hex [nrf91_read_memory_padded 0x20000010 1] + set prefix "0x" + + set hexAlphaNumeric [regsub -all $prefix $hex ""] + set hexAlphaReversed "" + set hexAlphaNumericLen [string length $hexAlphaNumeric] + for {set i 0} {$i < [expr $hexAlphaNumericLen/2]} {incr i} { + set stInd [expr $hexAlphaNumericLen-($i+1)*2] + set endInd [expr $hexAlphaNumericLen-($i)*2-1] + set byteStr [string range $hexAlphaNumeric $stInd $endInd] + append hexAlphaReversed $byteStr + } + set hexResult [string toupper $hexAlphaReversed] + string range $hexResult 0 end-1 +} + + +proc nrf91_modem_verify_digest_read {} { + set hex [nrf91_read_memory_padded 0x20000010 8] + set prefix "0x" + set hexAlphaNumeric [regsub -all $prefix $hex ""] + set hexAlphaNumericUnif [regsub -all " " $hexAlphaNumeric ""] + return [string toupper $hexAlphaNumericUnif] +} + +proc load_image_hex {fname foffset address length } { + # Load data from fname filename at foffset offset to + # target at address. Load at most length bytes. + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts [format "load_image %s %x ihex %x %x" $fname [expr {$address - $foffset}] $address $length] + } + load_image $fname [expr {$address - $foffset}] ihex $address $length +} + +set NRF91_UTIL_PYTHON [find target/nrf91_mfw_utils.cfg] + +proc nrf91_probe_sections_info {SEGMENT_FILE} { + exec python $::NRF91_UTIL_PYTHON $SEGMENT_FILE +} + +proc nrf91_probe_no_sections {SEGMENT_FILE} { + exec python $::NRF91_UTIL_PYTHON $SEGMENT_FILE -n -m +} + +proc nrf91_probe_probe_section_address {SEGMENT_FILE SECTION} { + set res [exec python $::NRF91_UTIL_PYTHON $SEGMENT_FILE -i [format "%d" $SECTION] -m] + scan $res "%d %d" address size + return $address +} + +proc nrf91_probe_probe_section_size {SEGMENT_FILE SECTION} { + set res [exec python $::NRF91_UTIL_PYTHON $SEGMENT_FILE -i [format "%d" $SECTION] -m] + scan $res "%d %d" address size + return $size +} + +proc nrf91_upload_section_legacy {SEGMENT_FILE SECTION_START SECTION_LENGTH} { + + set currentBufferOffset 0 + set curAddress 0 + set blockSize 0x10000 + + while {$curAddress < $SECTION_LENGTH} { + if { $SECTION_LENGTH - $curAddress < $blockSize} { + set blockSize [expr $SECTION_LENGTH-$curAddress] + } + set CURRENT_SECTION_START [expr $SECTION_START+$curAddress] + # Current chunk + set LRES [load_image_hex $SEGMENT_FILE $CURRENT_SECTION_START [expr 0x20000018] $blockSize] + + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts $LRES + } + set WRITTEN [scan $LRES %d] + + nrf91_mfw_write_memory 0x20000010 $CURRENT_SECTION_START + nrf91_mfw_write_memory 0x20000014 $WRITTEN + + #NVMC Write Enable -> True + nrf91_mfw_write_memory 0x50039504 0x1 + nrf91_mfw_write_memory 0x50039504 0x1 + + #Write command to the modem + nrf91_mfw_write_memory 0x2000000C 0x03 + #Start IPC + nrf91_mfw_write_memory 0x4002A004 0x01 + + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts [format "Started IPC 0x%x/0x%x -> 0x%x of 0x%x" $curAddress $SECTION_LENGTH 0x20000018 $CURRENT_SECTION_START] + } + + #Wait for Event + set EVT $::EVENT_FAULT + while {1} { + set EVT [nrf91_poll_modem_ctrl_event] + if {$EVT != $::EVENT_NONE} { + break + } + } + if {$EVT == $::EVENT_FAULT} { + error "Segment file upload failed" + } + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts [format "Confirmed IPC 0x%x/0x%x" $curAddress $SECTION_LENGTH] + } + set curAddress [expr $curAddress+$WRITTEN] + } +} + +proc nrf91_upload_section {SEGMENT_FILE SECTION_START SECTION_LENGTH} { + + set currentBufferOffset 0 + set curAddress 0 + set blockSize 0xE000 + + if { $SECTION_LENGTH - $curAddress < $blockSize} { + set blockSize [expr $SECTION_LENGTH-$curAddress] + } + set CURRENT_SECTION_START [expr $SECTION_START+$curAddress] + set CURRENT_BUFFER [expr 0x2000001C+$currentBufferOffset] + set LRES [load_image_hex $SEGMENT_FILE $CURRENT_SECTION_START $CURRENT_BUFFER $blockSize] + + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts $LRES + } + set WRITTEN [scan $LRES %d] + + while {$curAddress < $SECTION_LENGTH} { + nrf91_clear_modem_ctrl_events + # Current chunk + nrf91_mfw_write_memory 0x20000010 $CURRENT_SECTION_START + nrf91_mfw_write_memory 0x20000014 $WRITTEN + nrf91_mfw_write_memory 0x20000018 $currentBufferOffset + nrf91_mfw_write_memory 0x2000000C 0x09 + #Start IPC + nrf91_mfw_write_memory 0x4002A004 0x01 + + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts [format "Started IPC 0x%x/0x%x -> 0x%x of 0x%x" $curAddress $SECTION_LENGTH $CURRENT_BUFFER $CURRENT_SECTION_START] + } + + set curAddress [expr $curAddress+$WRITTEN] + if {$curAddress < $SECTION_LENGTH} { + if {$currentBufferOffset == 0x0} { + set currentBufferOffset 0xE000 + } else { + set currentBufferOffset 0 + } + if { $SECTION_LENGTH - $curAddress < $blockSize} { + set blockSize [expr $SECTION_LENGTH-$curAddress] + } + set CURRENT_SECTION_START [expr $SECTION_START+$curAddress] + set CURRENT_BUFFER [expr 0x2000001C+$currentBufferOffset] + set LRES [load_image_hex $SEGMENT_FILE $CURRENT_SECTION_START $CURRENT_BUFFER $blockSize] + + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts $LRES + } + set WRITTEN [scan $LRES %d] + } + + #Wait for Event + set EVT [nrf91_wait_for_modem_event] + if {$EVT == $::EVENT_FAULT} { + error "Segment file upload failed" + } + if {$::MODEM_FIRMWARE_UPDATE_DEBUG} { + puts [format "Confirmed IPC 0x%x/0x%x" $curAddress $SECTION_LENGTH] + } + } +} + +proc nrf91_upload_segment {SEGMENT_FILE bufferedUpload} { + set SECTIONS [nrf91_probe_no_sections $SEGMENT_FILE] + puts [format "Uploading segment file %s" $SEGMENT_FILE] + puts [ nrf91_probe_sections_info $SEGMENT_FILE ] + + for {set i 0} {$i < $SECTIONS} {incr i} { + puts [format "Uploading section %d/%d" [expr $i+1] $SECTIONS] + set SECTION_ADDRESS [ nrf91_probe_probe_section_address $SEGMENT_FILE $i ] + set SECTION_SIZE [ nrf91_probe_probe_section_size $SEGMENT_FILE $i ] + if {$bufferedUpload} { + nrf91_upload_section $SEGMENT_FILE $SECTION_ADDRESS $SECTION_SIZE + } else { + nrf91_upload_section_legacy $SEGMENT_FILE $SECTION_ADDRESS $SECTION_SIZE + } + } +} + +proc nrf91_verify_segements { SEGMENT_VERIFY_FILE } { + set fp [open $SEGMENT_VERIFY_FILE r] + set SEGMENTS 0 + set SEGMENTS_ADDRESES {} + set SEGMENTS_SIZES {} + set DIGEST {} + + while { [gets $fp SEGMENT_VERIFY_DATA_LINE] >= 0 } { + set result [regexp {^Range: (0[xX][0-9a-fA-F]+)--(0[xX][0-9a-fA-F]+)\s+SHA256:\s+([0-9a-fA-F]+)} $SEGMENT_VERIFY_DATA_LINE whole_match M_START_ADDRESS M_END_ADDRESS M_DIGIEST] + if {$result == 1} { + set M_START_ADDRESS_NUM [scan $M_START_ADDRESS %x] + set M_END_ADDRESS_NUM [scan $M_END_ADDRESS %x] + lappend SEGMENTS_ADDRESES $M_START_ADDRESS_NUM + lappend SEGMENTS_SIZES [expr $M_END_ADDRESS_NUM+1-$M_START_ADDRESS_NUM] + lappend DIGEST $M_DIGIEST + incr SEGMENTS + } + } + close $fp + nrf91_clear_modem_ctrl_events + + for {set i 0} {$i < $SEGMENTS} {incr i} { + nrf91_mfw_write_memory 0x2000000C 0x7 + puts [format "Validating segment: 0x%x size: 0x%x" [lindex $SEGMENTS_ADDRESES $i] [lindex $SEGMENTS_SIZES $i]] + nrf91_mfw_write_memory [expr 0x20000014] [lindex $SEGMENTS_ADDRESES $i] + nrf91_mfw_write_memory [expr 0x20000018] [lindex $SEGMENTS_SIZES $i] + + nrf91_mfw_write_memory 0x20000010 1 + nrf91_mfw_write_memory 0x4002A004 0x1 + + set EVT [nrf91_wait_for_modem_event] + if {$EVT == $::EVENT_FAULT} { + error "Verify Segment failed" + } + + set MODEM_DIGEST [nrf91_modem_verify_digest_read] + set EXPECT_DIGEST [lindex $DIGEST $i] + if { $MODEM_DIGEST != $EXPECT_DIGEST} { + error "Modem verification failed" [format "Expected digest: '%s' - Got: '%s'" $EXPECT_DIGEST $MODEM_DIGEST] + } + } + puts "Modem Verified" +} + +proc nrf91_flash_ipc_loader {IPC_DFU_FILENAME} { + # Load image to RAM + load_image $IPC_DFU_FILENAME 0 ihex + nrf91_mfw_write_memory 0x4002A004 0x1 + + #Wait for Event + set EVT [nrf91_wait_for_modem_event] + + if {$EVT == $::EVENT_FAULT} { + error "Modem firmware IPC DFU failed" + } + puts "Modem firmware IPC DFU Done" +} + +proc nrf91_flash_modem {MFW_FILE args} { + poll off + + set bufferedUpload 0 + if {"--buffered" in $args} { + set bufferedUpload 1 + } + + set MFW_FOLDER [exec mktemp -d] + exec unzip $MFW_FILE -d $MFW_FOLDER + set SEGMENT_FILES [glob [file join $MFW_FOLDER firmware.update.image.segments.*]] + + #Setting up the Modem + # Step 1 + # According to nrfjprog + nrf91_mfw_write_memory 0x500038A8 0x00 + + # Step 2 + nrf91_mfw_write_memory 0x4002A514 0x00000002 + nrf91_mfw_write_memory 0x4002A51C 0x00000008 + nrf91_mfw_write_memory 0x4002A610 0x21000000 + nrf91_mfw_write_memory 0x4002A614 0x00000000 + nrf91_mfw_write_memory 0x4002A590 0x00000001 + nrf91_mfw_write_memory 0x4002A598 0x00000004 + nrf91_mfw_write_memory 0x4002A5A0 0x00000010 + + # Step 3 Mark ram non secure + for {set i 0} {$i < 32} {incr i} { + nrf91_mfw_write_memory [expr 0x50003700+$i*4] 0x7 + } + + # Step 4 + nrf91_mfw_write_memory 0x20000000 0x80010000 + nrf91_mfw_write_memory 0x20000004 0x2100000C + nrf91_mfw_write_memory 0x20000008 0x0003FC00 + + # # Step 5 + nrf91_mfw_write_memory 0x50005610 0 + nrf91_mfw_write_memory 0x50005614 1 + nrf91_mfw_write_memory 0x50005610 1 + nrf91_mfw_write_memory 0x50005614 0 + nrf91_mfw_write_memory 0x50005610 0 + + # #HFXO SRC + # nrf91_mfw_write_memory 0x00FF801C 16 {0xE} + # #HFCO CNT + # nrf91_mfw_write_memory 0x00FF8020 16 0x20 + nrf91_clear_modem_ctrl_events + + set MODEM_DIGEST [ nrf91_modem_digest_read_prefix ] + set IPC_DFU_DILE [glob [format "%s/%s.ipc_dfu.signed_*" $MFW_FOLDER $MODEM_DIGEST]] + puts $IPC_DFU_DILE + set result [regexp {(\d+)\.(\d+)\.(\d+)\.ihex} $IPC_DFU_DILE whole_match M_IPC_MAJOR M_IPC_MINOR M_IPC_PATCH] + puts $result + if {$result != 1} { + error "Failed to detect IPC Loader version" + } + + set IPC_MAJOR [scan $M_IPC_MAJOR %d] + set IPC_MINOR [scan $M_IPC_MINOR %d] + set IPC_PATCH [scan $M_IPC_PATCH %d] + + nrf91_flash_ipc_loader $IPC_DFU_DILE + + if { ($IPC_MAJOR > 1) || (($IPC_MAJOR == 1) && ($IPC_MINOR >= 2)) } { + puts "Detected IPC Loader with buffered support enabling" + set bufferedUpload 1 + } + + foreach SEGMENT_FILE $SEGMENT_FILES { + nrf91_upload_segment $SEGMENT_FILE $bufferedUpload + } + + # puts "Modem firmware Segments Done" + nrf91_verify_segements [format "%s/firmware.update.image.digest.txt" $MFW_FOLDER] + poll on +} + +add_help_text nrf91_flash_modem "nRF91 update modem" \ No newline at end of file diff --git a/tcl/target/nrf91_mfw_utils.cfg b/tcl/target/nrf91_mfw_utils.cfg new file mode 100644 index 0000000000..0debdf4c3c --- /dev/null +++ b/tcl/target/nrf91_mfw_utils.cfg @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# + +import argparse +from intelhex import IntelHex + +def align_address(address, page_size): + """Align the address to the nearest page boundary.""" + return (address // page_size) * page_size + +def extract_contiguous_sections(hex_data, page_size): + sections = [] + current_section_start = None + current_section_end = None + + for start, stop in sorted(hex_data.segments()): + address = start + size = stop-start + if current_section_start is None: + current_section_start = align_address(address, page_size) + current_section_end = current_section_start + size + else: + if address > current_section_end: + sections.append((current_section_start, current_section_end - current_section_start)) + current_section_start = align_address(address, page_size) + current_section_end = current_section_start + size + else: + current_section_end = max(current_section_end, address + 1) + + if current_section_start is not None: + sections.append((current_section_start, current_section_end - current_section_start)) + + return sections + +def format_output(index, address, size, machine_readable): + if machine_readable: + return f"{address} {size}" + else: + return f"Section {index}:\nAddress: 0x{address:08X}\nSize: {size / 1024:.2f} KB\n" + +def print_selected_section(index, section, machine_readable): + print(format_output(index, section[0], section[1], machine_readable)) + +def list_sections_only(sections, machine_readable): + if machine_readable: + print(f"{len(sections)}") + else: + print(f"Number of Sections: {len(sections)}") + +def main(): + parser = argparse.ArgumentParser(description="Process HEX file and print contiguous sections.") + parser.add_argument("hex_file", help="Path to the HEX file") + parser.add_argument("-i", "--index", type=int, help="Optional index of the selected section to print") + parser.add_argument("-p", "--page", type=int, default=0x1000, help="Used to align the sections") + parser.add_argument("-m", "--machine-readable", action="store_true", help="Output in machine-readable format") + parser.add_argument("-n", "--list-sections-only", action="store_true", help="List only the number of sections") + args = parser.parse_args() + + hex_file_path = args.hex_file + selected_index = args.index + machine_readable = args.machine_readable + list_sections_only_flag = args.list_sections_only + page_size = args.page + + # Read the HEX file + hex_data = IntelHex(hex_file_path) + + # Extract contiguous sections + sections = extract_contiguous_sections(hex_data, page_size) + + # List only the number of sections + if list_sections_only_flag: + list_sections_only(sections, machine_readable) + else: + # Print selected section if specified + if selected_index is not None and selected_index < len(sections): + print_selected_section(selected_index, sections[selected_index], machine_readable) + else: + # Print all section information + for index, section in enumerate(sections, start=1): + print(format_output(index, section[0], section[1], machine_readable)) + +if __name__ == "__main__": + main() --