This is an automated email from Gerrit.

"Anton D. Kachalov <mo...@ya.ru>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/7404

-- gerrit

commit d2d6c476a1673db293f27011d1fcaa4edfb6a415
Author: Nguyen Hoan Hoang <hnh...@i-syst.com>
Date:   Tue Mar 10 16:34:20 2020 -0400

    Add support for Nordic nRF9160.
    
    Change-Id: I12ecd4332ff4b6cf6522b45023af358a8c7c4b6f
    Signed-off-by: Anton D. Kachalov <mo...@ya.ru>

diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index f04f0d206a..499e445fcf 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -48,6 +48,7 @@ NOR_DRIVERS = \
        %D%/non_cfi.c \
        %D%/npcx.c \
        %D%/nrf5.c \
+       %D%/nrf91.c \
        %D%/numicro.c \
        %D%/ocl.c \
        %D%/pic32mx.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index b9353d8208..7410e6c600 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -48,6 +48,7 @@ extern const struct flash_driver niietcm4_flash;
 extern const struct flash_driver npcx_flash;
 extern const struct flash_driver nrf5_flash;
 extern const struct flash_driver nrf51_flash;
+extern const struct flash_driver nrf91_flash;
 extern const struct flash_driver numicro_flash;
 extern const struct flash_driver ocl_flash;
 extern const struct flash_driver pic32mx_flash;
@@ -124,6 +125,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &npcx_flash,
        &nrf5_flash,
        &nrf51_flash,
+       &nrf91_flash,
        &numicro_flash,
        &ocl_flash,
        &pic32mx_flash,
diff --git a/src/flash/nor/nrf91.c b/src/flash/nor/nrf91.c
new file mode 100644
index 0000000000..15f7924511
--- /dev/null
+++ b/src/flash/nor/nrf91.c
@@ -0,0 +1,546 @@
+/***************************************************************************
+ *   Copyright (C) 2020 I-SYST inc.                                        *
+ *   hnh...@i-syst.com                                                     *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <helper/types.h>
+#include <helper/time_support.h>
+
+#define NRF91_FLASH_BASE                               0x00000000
+
+// Factory Information Configuration Registers
+#define NRF91_FICR_BASE                                0x00ff0000
+#define NRF91_FICR_DEVICEID0           (NRF91_FICR_BASE + 0x204)
+#define NRF91_FICR_DEVICEID1           (NRF91_FICR_BASE + 0x208)
+#define NRF91_FICR_INFO_PART           (NRF91_FICR_BASE + 0x20C)
+#define NRF91_FICR_INFO_VARIANT                (NRF91_FICR_BASE + 0x210)
+#define NRF91_FICR_INFO_PACKAGE                (NRF91_FICR_BASE + 0x214)
+#define NRF91_FICR_INFO_RAM                    (NRF91_FICR_BASE + 0x218)
+#define NRF91_FICR_INFO_FLASH          (NRF91_FICR_BASE + 0x21C)
+#define NRF91_FICR_CODEPAGESIZE                (NRF91_FICR_BASE + 0x220)
+#define NRF91_FICR_CODESIZE                    (NRF91_FICR_BASE + 0x224)
+#define NRF91_FICR_DEVICETYPE          (NRF91_FICR_BASE + 0x228)
+
+// User Information Configuration Regsters
+#define NRF91_UICR_BASE                                0x00ff8000
+#define NRF91_UICR_APPROTECT           (NRF91_UICR_BASE + 0x000)
+#define NRF91_UICR_SECUREAPPROTECT     (NRF91_UICR_BASE + 0x02C)
+#define NRF91_UICR_ERASEPROTECT                (NRF91_UICR_BASE + 0x030)
+
+// Non-Volatile Memory Controller Registers
+#define NRF91_NVMC_BASE                                0x50039000
+#define NRF91_NVMC_BASE_NS                     0x40039000
+
+#define NRF91_NVMC_READY                       (NRF91_NVMC_BASE + 0x400)
+#define NRF91_NVMC_CONFIG                      (NRF91_NVMC_BASE + 0x504)
+#define NRF91_NVMC_ERASEALL                    (NRF91_NVMC_BASE + 0x50C)
+#define NRF91_NVMC_ERASEUICR           (NRF91_NVMC_BASE + 0x514)
+
+#define NRF91_NVMC_CONFIG_REN          0
+#define NRF91_NVMC_CONFIG_WEN          1
+#define NRF91_NVMC_CONFIG_EEN          2
+
+#pragma pack(push, 4)
+typedef struct nrf_ficr_info {
+       uint64_t id;
+       uint32_t part;
+       uint32_t variant;
+       uint32_t package;
+       uint32_t ram;
+       uint32_t flash;
+       uint32_t code_page_size;
+       uint32_t code_size;
+       uint32_t device_type;
+} nrf_ficr_info_t;
+#pragma pack(pop)
+
+typedef struct nrf91_chip {
+       uint32_t refcount;
+       bool probed;
+       bool ficr_info_valid;
+       nrf_ficr_info_t ficr_info;
+       uint32_t flash_size_kb;
+       uint32_t ram_size_kb;
+       struct target *target;
+} nrf91_chip_t;
+
+const struct flash_driver nrf91_flash;
+
+static int nrf91_probe(struct flash_bank *bank);
+
+static nrf91_chip_t *get_active_chip(struct flash_bank *bank)
+{
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return NULL;
+       }
+
+       nrf91_chip_t *chip = bank->driver_priv;
+
+       if (chip->probed == true) {
+               return chip;
+       }
+
+       if (nrf91_probe(bank) == ERROR_OK) {
+               return chip;
+       }
+
+       return NULL;
+}
+
+static int nrf91_wait_for_nvmc(nrf91_chip_t *chip)
+{
+       uint32_t ready;
+       int res;
+       int timeout_ms = 340;
+       int64_t ts_start = timeval_ms();
+
+       do {
+               res = target_read_u32(chip->target, NRF91_NVMC_READY, &ready);
+
+               if (ready == 0x00000001)
+               {
+                       return ERROR_OK;
+               }
+
+               keep_alive();
+
+       } while ((timeval_ms()-ts_start) < timeout_ms);
+
+       LOG_DEBUG("Timed out waiting for NVMC_READY");
+       return ERROR_FLASH_BUSY;
+}
+
+static int nrf91_nvmc_erase_enable(nrf91_chip_t *chip)
+{
+       int res;
+       res = target_write_u32(chip->target,
+                              NRF91_NVMC_CONFIG,
+                              NRF91_NVMC_CONFIG_EEN);//|NRF91_NVMC_CONFIG_WEN);
+
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to enable erase operation");
+               return res;
+       }
+
+       /*
+         According to NVMC examples in Nordic SDK busy status must be
+         checked after writing to NVMC_CONFIG
+        */
+       res = nrf91_wait_for_nvmc(chip);
+       if (res != ERROR_OK)
+               LOG_ERROR("Erase enable did not complete");
+
+       return res;
+}
+
+static int nrf91_nvmc_write_enable(nrf91_chip_t *chip)
+{
+       int res;
+       res = target_write_u32(chip->target,
+                              NRF91_NVMC_CONFIG,
+                              NRF91_NVMC_CONFIG_WEN);
+
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to enable write operation");
+               return res;
+       }
+
+       /*
+         According to NVMC examples in Nordic SDK busy status must be
+         checked after writing to NVMC_CONFIG
+        */
+       res = nrf91_wait_for_nvmc(chip);
+       if (res != ERROR_OK)
+               LOG_ERROR("Write enable did not complete");
+
+       return res;
+}
+
+static int nrf91_nvmc_read_only(nrf91_chip_t *chip)
+{
+       int res;
+       res = target_write_u32(chip->target,
+                              NRF91_NVMC_CONFIG,
+                              NRF91_NVMC_CONFIG_REN);
+
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to enable read-only operation");
+               return res;
+       }
+       /*
+         According to NVMC examples in Nordic SDK busy status must be
+         checked after writing to NVMC_CONFIG
+        */
+       res = nrf91_wait_for_nvmc(chip);
+       if (res != ERROR_OK)
+               LOG_ERROR("Read only enable did not complete");
+
+       return res;
+}
+
+static int nrf91_protect_check(struct flash_bank *bank)
+{
+       uint32_t clenr0 = 0xFFFFFFFFU;
+
+       /* UICR cannot be write protected so just return early */
+       if (bank->base == NRF91_UICR_BASE)
+               return ERROR_OK;
+
+       nrf91_chip_t *chip = bank->driver_priv;
+       assert(chip != NULL);
+
+       for (unsigned int i = 0; i < bank->num_sectors; i++)
+               bank->sectors[i].is_protected =
+                       clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < 
clenr0;
+
+       return ERROR_OK;
+}
+
+static int nrf91_protect(struct flash_bank *bank, int set, unsigned int first, 
unsigned int last)
+{
+       nrf91_chip_t *chip = get_active_chip(bank);
+
+       if (chip == NULL) {
+               return ERROR_FAIL;
+       }
+
+       /* UICR cannot be write protected so just bail out early */
+       if (bank->base == NRF91_UICR_BASE)
+               return ERROR_FAIL;
+
+       if (first != 0) {
+               LOG_ERROR("Code region 0 must start at the begining of the 
bank");
+               return ERROR_FAIL;
+       }
+
+       nrf91_protect_check(bank);
+
+       return ERROR_OK;
+}
+
+static int nrf91_read_ficr_info(nrf91_chip_t *chip)
+{
+       int res;
+       nrf_ficr_info_t ficr;
+
+       chip->ficr_info_valid = false;
+
+       res = target_read_buffer(chip->target, NRF91_FICR_DEVICEID0, 
sizeof(nrf_ficr_info_t), (uint8_t*)&ficr);
+       if (res != ERROR_OK) {
+               LOG_INFO("Couldn't read FICR INFO registers");
+               return res;
+       }
+
+       if (ficr.part != 0x9160 && ficr.part != 0x9120) {
+               LOG_INFO("Wrong device %X", ficr.part);
+               res = target_read_u32(chip->target, NRF91_FICR_INFO_PART, 
&ficr.part);
+               LOG_INFO("PART %X", ficr.part);
+
+               return ERROR_FAIL;
+       }
+
+       memcpy(&chip->ficr_info, &ficr, sizeof(nrf_ficr_info_t));
+
+       chip->ram_size_kb = ficr.ram;
+       chip->flash_size_kb = ficr.flash;
+
+       chip->ficr_info_valid = true;
+
+       return ERROR_OK;
+}
+
+static int nrf91_info(struct flash_bank *bank, struct command_invocation *cmd)
+{
+       nrf91_chip_t *chip = bank->driver_priv;
+       int res = ERROR_OK;
+
+       if (chip->ficr_info_valid == false) {
+               res = nrf91_read_ficr_info(chip);
+       }
+
+       if (res == ERROR_OK) {
+               char variant[5];
+               memcpy(variant, &chip->ficr_info.variant, 4);
+               variant[4] = 0;
+               command_print_sameline(cmd, "nRF%X-%s, %uKB FLASH, %uKB RAM, 
DevId : 0x%016" PRIX64,
+                               chip->ficr_info.part, variant,
+                               chip->ficr_info.flash, chip->ficr_info.ram,
+                               chip->ficr_info.id);
+       }
+
+       return res;
+}
+
+static int nrf91_probe(struct flash_bank *bank)
+{
+       nrf91_chip_t *chip = bank->driver_priv;
+
+       (void)nrf91_read_ficr_info(chip);
+
+       if (chip->ficr_info_valid == false) {
+               LOG_INFO("Unknown device");
+
+               return ERROR_FAIL;
+       }
+
+       free(bank->sectors);
+
+       if (bank->base == NRF91_FLASH_BASE) {
+               /* Sanity check */
+               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");
+
+               bank->num_sectors = chip->ficr_info.code_size;
+               bank->size = bank->num_sectors * chip->ficr_info.code_page_size;
+
+               bank->sectors = alloc_block_array(0, 
chip->ficr_info.code_page_size, bank->num_sectors);
+               if (!bank->sectors)
+                       return ERROR_FAIL;
+
+               nrf91_protect_check(bank);
+
+               chip->probed = true;
+
+       } else {
+               bank->num_sectors = 1;
+               bank->size = chip->ficr_info.code_page_size;
+
+               bank->sectors = alloc_block_array(0, 
chip->ficr_info.code_page_size, bank->num_sectors);
+               if (!bank->sectors)
+                       return ERROR_FAIL;
+
+               bank->sectors[0].is_protected = 0;
+
+               chip->probed = true;
+       }
+
+       return ERROR_OK;
+}
+
+static int nrf91_auto_probe(struct flash_bank *bank)
+{
+       nrf91_chip_t *chip = bank->driver_priv;
+
+       if (chip == NULL) {
+               return ERROR_FAIL;
+       }
+
+       if (chip->probed == false) {
+               return nrf91_probe(bank);
+       }
+
+       return ERROR_OK;
+}
+
+static int nrf91_erase_all(nrf91_chip_t *chip)
+{
+       int res = nrf91_nvmc_erase_enable(chip);
+       if (res == ERROR_OK)
+       {
+               res = target_write_u32(chip->target, NRF91_NVMC_ERASEALL, 1);
+               res = nrf91_wait_for_nvmc(chip);
+               nrf91_nvmc_read_only(chip);
+       }
+       return res;
+}
+
+static int nrf91_erase_page(struct flash_bank *bank,
+                                                       nrf91_chip_t *chip,
+                                                       struct flash_sector 
*sector)
+{
+       int res;
+
+       res = nrf91_nvmc_erase_enable(chip);
+       if (res == ERROR_OK)
+       {
+               res = target_write_u32(chip->target, sector->offset, 
0xFFFFFFFF);
+               if (res == ERROR_OK)
+               {
+                       res = nrf91_wait_for_nvmc(chip);
+               }
+
+               return nrf91_nvmc_read_only(chip);
+       }
+       LOG_ERROR("** Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32,
+                       sector->offset, 0xFFFFFFFF);
+
+       return res;
+}
+static int nrf91_write(struct flash_bank *bank, const uint8_t *buffer,
+                                       uint32_t offset, uint32_t count)
+{
+       nrf91_chip_t *chip = get_active_chip(bank);
+       int res;
+
+       if (chip == NULL) {
+               return ERROR_FAIL;
+       }
+
+       assert(offset % 4 == 0);
+       assert(count % 4 == 0);
+
+       res = nrf91_nvmc_write_enable(chip);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to enable write to nrf91 flash");
+               return res;
+       }
+       res = target_write_buffer(chip->target, bank->base + offset, count, 
buffer);
+       if (res != ERROR_OK) {
+               LOG_ERROR("nrf91 write failed");
+       }
+
+       nrf91_nvmc_read_only(chip);
+
+       return res;
+}
+
+static int nrf91_erase(struct flash_bank *bank, unsigned int first, unsigned 
int last)
+{
+       int res = ERROR_OK;
+       nrf91_chip_t *chip = get_active_chip(bank);
+
+       if (chip == NULL)
+       {
+               return ERROR_FAIL;
+       }
+
+       /* For each sector to be erased */
+       for (unsigned int s = first; s <= last && res == ERROR_OK; s++)
+               res = nrf91_erase_page(bank, chip, &bank->sectors[s]);
+
+       return res;
+}
+
+static void nrf91_free_driver_priv(struct flash_bank *bank)
+{
+       nrf91_chip_t *chip = bank->driver_priv;
+       if (chip == NULL)
+               return;
+
+       chip->refcount--;
+       if (chip->refcount == 0) {
+               free(chip);
+               bank->driver_priv = NULL;
+       }
+}
+
+FLASH_BANK_COMMAND_HANDLER(nrf91_flash_bank_command)
+{
+       struct flash_bank *bank_iter;
+       nrf91_chip_t *chip = NULL;
+
+       if (bank->base != NRF91_FLASH_BASE && bank->base != NRF91_UICR_BASE) {
+               LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
+               return ERROR_FAIL;
+       }
+
+       /* iterate over nrf9 banks of same target */
+       for (bank_iter = flash_bank_list(); bank_iter; bank_iter = 
bank_iter->next) {
+               if (bank_iter->driver == &nrf91_flash && bank_iter->target == 
bank->target)
+               {
+                       chip = bank_iter->driver_priv;
+               }
+       }
+
+       if (!chip) {
+               /* Create a new chip */
+               chip = calloc(1, sizeof(*chip));
+               if (!chip)
+                       return ERROR_FAIL;
+
+               chip->target = bank->target;
+       }
+
+       chip->refcount++;
+       chip->probed = false;
+       bank->driver_priv = chip;
+       bank->write_start_alignment = bank->write_end_alignment = 4;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(nrf91_handle_mass_erase_command)
+{
+       int res;
+       struct flash_bank *bank = NULL;
+       struct target *target = get_current_target(CMD_CTX);
+
+       res = get_flash_bank_by_addr(target, NRF91_FLASH_BASE, true, &bank);
+       if (res != ERROR_OK)
+               return res;
+
+       assert(bank != NULL);
+
+       nrf91_chip_t *chip = get_active_chip(bank);
+       if (chip == NULL)
+       {
+               return ERROR_FAIL;
+       }
+
+       res = nrf91_erase_all(chip);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to erase the chip");
+               nrf91_protect_check(bank);
+               return res;
+       }
+
+       res = nrf91_protect_check(bank);
+       if (res != ERROR_OK) {
+               LOG_ERROR("Failed to check chip's write protection");
+               return res;
+       }
+
+       res = get_flash_bank_by_addr(target, NRF91_UICR_BASE, true, &bank);
+       if (res != ERROR_OK)
+               return res;
+
+       return ERROR_OK;
+}
+
+static const struct command_registration nrf91_command_handlers[] = {
+       {
+               .name           = "mass_erase",
+               .handler        = nrf91_handle_mass_erase_command,
+               .mode           = COMMAND_EXEC,
+               .help           = "Erase all flash contents of the chip.",
+               .usage          = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct flash_driver nrf91_flash = {
+       .name                   = "nrf91",
+       .commands               = nrf91_command_handlers,
+       .flash_bank_command     = nrf91_flash_bank_command,
+       .info                   = nrf91_info,
+       .erase                  = nrf91_erase,
+       .protect                = nrf91_protect,
+       .write                  = nrf91_write,
+       .read                   = default_flash_read,
+       .probe                  = nrf91_probe,
+       .auto_probe             = nrf91_auto_probe,
+       .erase_check            = default_flash_blank_check,
+       .protect_check          = nrf91_protect_check,
+       .free_driver_priv       = nrf91_free_driver_priv,
+};
diff --git a/tcl/target/nrf91.cfg b/tcl/target/nrf91.cfg
new file mode 100644
index 0000000000..d5daf3c87d
--- /dev/null
+++ b/tcl/target/nrf91.cfg
@@ -0,0 +1,42 @@
+#
+# 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] } {
+       cortex_m reset_config sysresetreq
+}
+
+flash bank $_CHIPNAME.flash nrf91 0x00000000 0 1 1 $_TARGETNAME
+flash bank $_CHIPNAME.uicr nrf91 0xff8000 0 1 1 $_TARGETNAME

-- 

Reply via email to