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()

-- 

Reply via email to