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/+/8062
-- gerrit commit 6491bb86bd2a72a6745251b667b5a74c6df16e86 Author: Tomáš Beneš <to...@dronetag.cz> Date: Sun Dec 31 14:38:39 2023 +0100 flash: nor: add support for Nordic nRF9160 Original patch by Tobias Rohde <t...@lobaro.com>, Anton D. Kachalov <mo...@ya.ru> Change-Id: I3c2a0745e9d7abc51bbefb0ba0a73b6e5122e0bd 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..a17af371be 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -5,6 +5,8 @@ * Andrey Smirnov <andrew.smir...@gmail.com> * * Angus Gratton <g...@projectgus.com> * * Erdem U. Altunyurt <spamjunkea...@gmail.com> * + * Tobias Rohde <t...@lobaro.com> * + * Anton D. Kachalov <mo...@yandex.ru> * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -12,7 +14,9 @@ #endif #include "imp.h" +#include <helper/align.h> #include <helper/binarybuffer.h> +#include <helper/bits.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <helper/types.h> @@ -23,155 +27,481 @@ #define WATCHDOG_REFRESH_VALUE 0x6e524635 enum { - NRF5_FLASH_BASE = 0x00000000, + NRFX_FLASH_BASE = 0x00000000, }; -enum nrf5_ficr_registers { - NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ - -#define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset) - - NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010), - NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014), - - NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028), - NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C), - NRF51_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), - NRF51_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), - NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), - NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), - NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), - - NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), - NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060), - NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064), - NRF5_FICR_ER0 = NRF5_FICR_REG(0x080), - NRF5_FICR_ER1 = NRF5_FICR_REG(0x084), - NRF5_FICR_ER2 = NRF5_FICR_REG(0x088), - NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C), - NRF5_FICR_IR0 = NRF5_FICR_REG(0x090), - NRF5_FICR_IR1 = NRF5_FICR_REG(0x094), - NRF5_FICR_IR2 = NRF5_FICR_REG(0x098), - NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C), - NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0), - NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4), - NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8), - - NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), - NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), - NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), - NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), - NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), - NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), - NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), - NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), - NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), - NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), - NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), +/* Factory Information Configuration Registers */ +#define NRF5_FICR_BASE 0x10000000 +#define NRF9_FICR_BASE 0x00ff0000 + +#define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + (offset)) +#define NRF9_FICR_REG(offset) (NRF9_FICR_BASE + (offset)) + +#define NRFX_UNIMPLEMENTED 0xffffffff + +/* + * The following nrfx_<unit>_registers enums contain "virtual" + * registers definitions: they just link each register's name to an integer + * index. The index is made of a 12bits progressive number ored with + * another number which represents the hw unit the register itself belongs to. + */ +#define REG_INDEX_BITS 12 + +#define REG_INDEX_MASK ((1 << REG_INDEX_BITS) - 1) + +#define FICR_ID (0 << REG_INDEX_BITS) +#define UICR_ID BIT(REG_INDEX_BITS) +#define NVMC_ID (2 << REG_INDEX_BITS) + +#define FICR_BASE FICR_ID +#define UICR_BASE UICR_ID +#define NVMC_BASE NVMC_ID + +#define reg_index(r) ((r) & REG_INDEX_MASK) + +enum nrfx_ficr_registers { + NRFX_FICR_CODEPAGESIZE = FICR_BASE, + NRFX_FICR_CODESIZE, + NRFX_FICR_CLENR0, + NRFX_FICR_PPFC, + NRFX_FICR_NUMRAMBLOCK, + NRFX_FICR_SIZERAMBLOCK0, + NRFX_FICR_SIZERAMBLOCK1, + NRFX_FICR_SIZERAMBLOCK2, + NRFX_FICR_SIZERAMBLOCK3, + NRFX_FICR_CONFIGID, + NRFX_FICR_DEVICEID0, + NRFX_FICR_DEVICEID1, + NRFX_FICR_ER0, + NRFX_FICR_ER1, + NRFX_FICR_ER2, + NRFX_FICR_ER3, + NRFX_FICR_IR0, + NRFX_FICR_IR1, + NRFX_FICR_IR2, + NRFX_FICR_IR3, + NRFX_FICR_DEVICEADDRTYPE, + NRFX_FICR_DEVICEADDR0, + NRFX_FICR_DEVICEADDR1, + NRFX_FICR_OVERRIDEN, + NRFX_FICR_NRF_1MBIT0, + NRFX_FICR_NRF_1MBIT1, + NRFX_FICR_NRF_1MBIT2, + NRFX_FICR_NRF_1MBIT3, + NRFX_FICR_NRF_1MBIT4, + NRFX_FICR_BLE_1MBIT0, + NRFX_FICR_BLE_1MBIT1, + NRFX_FICR_BLE_1MBIT2, + NRFX_FICR_BLE_1MBIT3, + NRFX_FICR_BLE_1MBIT4, + NRFX_FICR_INFO_PART, + NRFX_FICR_INFO_VARIANT, + NRFX_FICR_INFO_PACKAGE, + NRFX_FICR_INFO_RAM, + NRFX_FICR_INFO_FLASH, + NRFX_FICR_NREGS = ((NRFX_FICR_INFO_FLASH + 1) & REG_INDEX_MASK), +}; + +static const uint32_t nrf51_ficr_registers[] = { + [reg_index(NRFX_FICR_CODEPAGESIZE)] = NRF5_FICR_REG(0x010), + [reg_index(NRFX_FICR_CODESIZE)] = NRF5_FICR_REG(0x014), + + [reg_index(NRFX_FICR_CLENR0)] = NRF5_FICR_REG(0x028), + [reg_index(NRFX_FICR_PPFC)] = NRF5_FICR_REG(0x02C), + [reg_index(NRFX_FICR_NUMRAMBLOCK)] = NRF5_FICR_REG(0x034), + [reg_index(NRFX_FICR_SIZERAMBLOCK0)] = NRF5_FICR_REG(0x038), + [reg_index(NRFX_FICR_SIZERAMBLOCK1)] = NRF5_FICR_REG(0x03C), + [reg_index(NRFX_FICR_SIZERAMBLOCK2)] = NRF5_FICR_REG(0x040), + [reg_index(NRFX_FICR_SIZERAMBLOCK3)] = NRF5_FICR_REG(0x044), + + [reg_index(NRFX_FICR_CONFIGID)] = NRF5_FICR_REG(0x05C), + [reg_index(NRFX_FICR_DEVICEID0)] = NRF5_FICR_REG(0x060), + [reg_index(NRFX_FICR_DEVICEID1)] = NRF5_FICR_REG(0x064), + [reg_index(NRFX_FICR_ER0)] = NRF5_FICR_REG(0x080), + [reg_index(NRFX_FICR_ER1)] = NRF5_FICR_REG(0x084), + [reg_index(NRFX_FICR_ER2)] = NRF5_FICR_REG(0x088), + [reg_index(NRFX_FICR_ER3)] = NRF5_FICR_REG(0x08C), + [reg_index(NRFX_FICR_IR0)] = NRF5_FICR_REG(0x090), + [reg_index(NRFX_FICR_IR1)] = NRF5_FICR_REG(0x094), + [reg_index(NRFX_FICR_IR2)] = NRF5_FICR_REG(0x098), + [reg_index(NRFX_FICR_IR3)] = NRF5_FICR_REG(0x09C), + [reg_index(NRFX_FICR_DEVICEADDRTYPE)] = NRF5_FICR_REG(0x0A0), + [reg_index(NRFX_FICR_DEVICEADDR0)] = NRF5_FICR_REG(0x0A4), + [reg_index(NRFX_FICR_DEVICEADDR1)] = NRF5_FICR_REG(0x0A8), + + [reg_index(NRFX_FICR_OVERRIDEN)] = NRF5_FICR_REG(0x0AC), + [reg_index(NRFX_FICR_NRF_1MBIT0)] = NRF5_FICR_REG(0x0B0), + [reg_index(NRFX_FICR_NRF_1MBIT1)] = NRF5_FICR_REG(0x0B4), + [reg_index(NRFX_FICR_NRF_1MBIT2)] = NRF5_FICR_REG(0x0B8), + [reg_index(NRFX_FICR_NRF_1MBIT3)] = NRF5_FICR_REG(0x0BC), + [reg_index(NRFX_FICR_NRF_1MBIT4)] = NRF5_FICR_REG(0x0C0), + [reg_index(NRFX_FICR_BLE_1MBIT0)] = NRF5_FICR_REG(0x0EC), + [reg_index(NRFX_FICR_BLE_1MBIT1)] = NRF5_FICR_REG(0x0F0), + [reg_index(NRFX_FICR_BLE_1MBIT2)] = NRF5_FICR_REG(0x0F4), + [reg_index(NRFX_FICR_BLE_1MBIT3)] = NRF5_FICR_REG(0x0F8), + [reg_index(NRFX_FICR_BLE_1MBIT4)] = NRF5_FICR_REG(0x0FC), /* Following registers are available on nRF52 and on nRF51 since rev 3 */ - NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100), - NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104), - NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108), - NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C), - NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110), + [reg_index(NRFX_FICR_INFO_PART)] = NRF5_FICR_REG(0x100), + [reg_index(NRFX_FICR_INFO_VARIANT)] = NRF5_FICR_REG(0x104), + [reg_index(NRFX_FICR_INFO_PACKAGE)] = NRF5_FICR_REG(0x108), + [reg_index(NRFX_FICR_INFO_RAM)] = NRF5_FICR_REG(0x10C), + [reg_index(NRFX_FICR_INFO_FLASH)] = NRF5_FICR_REG(0x110), +}; + +static const uint32_t nrf52_ficr_registers[] = { + [reg_index(NRFX_FICR_CODEPAGESIZE)] = NRF5_FICR_REG(0x010), + [reg_index(NRFX_FICR_CODESIZE)] = NRF5_FICR_REG(0x014), + + [reg_index(NRFX_FICR_CLENR0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_PPFC)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NUMRAMBLOCK)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK3)] = NRFX_UNIMPLEMENTED, + + [reg_index(NRFX_FICR_CONFIGID)] = NRF5_FICR_REG(0x05C), + [reg_index(NRFX_FICR_DEVICEID0)] = NRF5_FICR_REG(0x060), + [reg_index(NRFX_FICR_DEVICEID1)] = NRF5_FICR_REG(0x064), + [reg_index(NRFX_FICR_ER0)] = NRF5_FICR_REG(0x080), + [reg_index(NRFX_FICR_ER1)] = NRF5_FICR_REG(0x084), + [reg_index(NRFX_FICR_ER2)] = NRF5_FICR_REG(0x088), + [reg_index(NRFX_FICR_ER3)] = NRF5_FICR_REG(0x08C), + [reg_index(NRFX_FICR_IR0)] = NRF5_FICR_REG(0x090), + [reg_index(NRFX_FICR_IR1)] = NRF5_FICR_REG(0x094), + [reg_index(NRFX_FICR_IR2)] = NRF5_FICR_REG(0x098), + [reg_index(NRFX_FICR_IR3)] = NRF5_FICR_REG(0x09C), + [reg_index(NRFX_FICR_DEVICEADDRTYPE)] = NRF5_FICR_REG(0x0A0), + [reg_index(NRFX_FICR_DEVICEADDR0)] = NRF5_FICR_REG(0x0A4), + [reg_index(NRFX_FICR_DEVICEADDR1)] = NRF5_FICR_REG(0x0A8), + + [reg_index(NRFX_FICR_OVERRIDEN)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT3)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT4)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT3)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT4)] = NRFX_UNIMPLEMENTED, + + [reg_index(NRFX_FICR_INFO_PART)] = NRF5_FICR_REG(0x100), + [reg_index(NRFX_FICR_INFO_VARIANT)] = NRF5_FICR_REG(0x104), + [reg_index(NRFX_FICR_INFO_PACKAGE)] = NRF5_FICR_REG(0x108), + [reg_index(NRFX_FICR_INFO_RAM)] = NRF5_FICR_REG(0x10C), + [reg_index(NRFX_FICR_INFO_FLASH)] = NRF5_FICR_REG(0x110), +}; + +static const uint32_t nrf91_ficr_registers[] = { + [reg_index(NRFX_FICR_CODEPAGESIZE)] = NRF9_FICR_REG(0x220), + [reg_index(NRFX_FICR_CODESIZE)] = NRF9_FICR_REG(0x224), + + [reg_index(NRFX_FICR_CLENR0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_PPFC)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NUMRAMBLOCK)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_SIZERAMBLOCK3)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_CONFIGID)] = NRFX_UNIMPLEMENTED, + + [reg_index(NRFX_FICR_DEVICEID0)] = NRF9_FICR_REG(0x204), + [reg_index(NRFX_FICR_DEVICEID1)] = NRF9_FICR_REG(0x208), + + [reg_index(NRFX_FICR_ER0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_ER1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_ER2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_ER3)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_IR0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_IR1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_IR2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_IR3)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_DEVICEADDRTYPE)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_DEVICEADDR0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_DEVICEADDR1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_OVERRIDEN)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT3)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_NRF_1MBIT4)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT2)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT3)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_FICR_BLE_1MBIT4)] = NRFX_UNIMPLEMENTED, + + [reg_index(NRFX_FICR_INFO_PART)] = NRF9_FICR_REG(0x20c), + [reg_index(NRFX_FICR_INFO_VARIANT)] = NRF9_FICR_REG(0x210), + [reg_index(NRFX_FICR_INFO_PACKAGE)] = NRF9_FICR_REG(0x214), + [reg_index(NRFX_FICR_INFO_RAM)] = NRF9_FICR_REG(0x218), + [reg_index(NRFX_FICR_INFO_FLASH)] = NRF9_FICR_REG(0x21c), +}; + +/* User Information Configuration Registers */ +#define NRF5_UICR_BASE 0x10001000 +#define NRF9_UICR_BASE 0x00ff8000 + +#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + (offset)) +#define NRF9_UICR_REG(offset) (NRF9_UICR_BASE + (offset)) +#define NRFX_UICR_SIZE 0x1000 + +enum nrfx_family { + NRFX_FAMILY_UNK = 0, + NRFX_FAMILY_5X = 0xff, + NRFX_FAMILY_51 = 51, + NRFX_FAMILY_52 = 52, + NRFX_FAMILY_91 = 91, }; -enum nrf5_uicr_registers { - NRF5_UICR_BASE = 0x10001000, /* User Information - * Configuration Registers */ +static inline uint32_t nrfx_uicr_base(enum nrfx_family family) +{ + switch (family) { + case NRFX_FAMILY_51: + case NRFX_FAMILY_52: + return NRF5_UICR_BASE; + case NRFX_FAMILY_91: + return NRF9_UICR_BASE; + default: + return NRFX_UNIMPLEMENTED; + } + return NRFX_UNIMPLEMENTED; +} -#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) +enum nrfx_uicr_registers { + NRFX_UICR_CLENR0 = UICR_BASE, + NRFX_UICR_RBPCONF, + NRFX_UICR_XTALFREQ, + NRFX_UICR_FWID, + NRFX_UICR_PSELRESET0, + NRFX_UICR_PSELRESET1, + NRFX_UICR_APPROTECT, + NRFX_UICR_NFCPINS, + NRFX_UICR_SECUREAPPROTECT, + NRFX_UICR_ERASEPROTECT, + NRFX_UICR_NREGS = ((NRFX_UICR_ERASEPROTECT + 1) & REG_INDEX_MASK), +}; - NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000), - NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004), - NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008), - NRF51_UICR_FWID = NRF5_UICR_REG(0x010), +static const uint32_t nrf51_uicr_registers[] = { + [reg_index(NRFX_UICR_CLENR0)] = NRF5_UICR_REG(0x000), + [reg_index(NRFX_UICR_RBPCONF)] = NRF5_UICR_REG(0x004), + [reg_index(NRFX_UICR_XTALFREQ)] = NRF5_UICR_REG(0x008), + [reg_index(NRFX_UICR_FWID)] = NRF5_UICR_REG(0x010), + [reg_index(NRFX_UICR_PSELRESET0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_PSELRESET1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_APPROTECT)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_NFCPINS)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_SECUREAPPROTECT)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_ERASEPROTECT)] = NRFX_UNIMPLEMENTED, }; -enum nrf5_nvmc_registers { - NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory - * Controller Registers */ +static const uint32_t nrf52_uicr_registers[] = { + [reg_index(NRFX_UICR_CLENR0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_RBPCONF)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_XTALFREQ)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_FWID)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_PSELRESET0)] = NRF5_UICR_REG(0x200), + [reg_index(NRFX_UICR_PSELRESET1)] = NRF5_UICR_REG(0x204), + [reg_index(NRFX_UICR_APPROTECT)] = NRF5_UICR_REG(0x208), + [reg_index(NRFX_UICR_NFCPINS)] = NRF5_UICR_REG(0x20C), + [reg_index(NRFX_UICR_SECUREAPPROTECT)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_ERASEPROTECT)] = NRFX_UNIMPLEMENTED, +}; -#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) +static const uint32_t nrf91_uicr_registers[] = { + [reg_index(NRFX_UICR_CLENR0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_RBPCONF)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_XTALFREQ)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_FWID)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_PSELRESET0)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_PSELRESET1)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_APPROTECT)] = NRF9_UICR_REG(0x000), + [reg_index(NRFX_UICR_NFCPINS)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_UICR_SECUREAPPROTECT)] = NRF9_UICR_REG(0x02C), + [reg_index(NRFX_UICR_ERASEPROTECT)] = NRF9_UICR_REG(0x030), +}; + +/* Non-Volatile Memory Controller Registers */ +#define NRF5_NVMC_BASE 0x4001E000 +#define NRF9_NVMC_BASE 0x50039000 + +#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + (offset)) +#define NRF9_NVMC_REG(offset) (NRF9_NVMC_BASE + (offset)) - NRF5_NVMC_READY = NRF5_NVMC_REG(0x400), - NRF5_NVMC_CONFIG = NRF5_NVMC_REG(0x504), - NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), - NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), - NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), +enum nrfx_nvmc_registers { + NRFX_NVMC_READY = NVMC_BASE, + NRFX_NVMC_CONFIG, + NRFX_NVMC_ERASEPAGE, + NRFX_NVMC_ERASEALL, + NRFX_NVMC_ERASEUICR, + NRFX_BPROT_BASE, +}; - NRF5_BPROT_BASE = 0x40000000, +enum nrfx_nvmc_config_bits { + NRFX_NVMC_CONFIG_REN = 0x00, + NRFX_NVMC_CONFIG_WEN = 0x01, + NRFX_NVMC_CONFIG_EEN = 0x02, }; -enum nrf5_nvmc_config_bits { - NRF5_NVMC_CONFIG_REN = 0x00, - NRF5_NVMC_CONFIG_WEN = 0x01, - NRF5_NVMC_CONFIG_EEN = 0x02, +static const uint32_t nrf5_nvmc_registers[] = { + [reg_index(NRFX_NVMC_READY)] = NRF5_NVMC_REG(0x400), + [reg_index(NRFX_NVMC_CONFIG)] = NRF5_NVMC_REG(0x504), + [reg_index(NRFX_NVMC_ERASEPAGE)] = NRF5_NVMC_REG(0x508), + [reg_index(NRFX_NVMC_ERASEALL)] = NRF5_NVMC_REG(0x50C), + [reg_index(NRFX_NVMC_ERASEUICR)] = NRF5_NVMC_REG(0x514), + [reg_index(NRFX_BPROT_BASE)] = 0x40000000, +}; +static const uint32_t nrf91_nvmc_registers[] = { + [reg_index(NRFX_NVMC_READY)] = NRF9_NVMC_REG(0x400), + [reg_index(NRFX_NVMC_CONFIG)] = NRF9_NVMC_REG(0x504), + [reg_index(NRFX_NVMC_ERASEPAGE)] = NRFX_UNIMPLEMENTED, + [reg_index(NRFX_NVMC_ERASEALL)] = NRF9_NVMC_REG(0x50C), + [reg_index(NRFX_NVMC_ERASEUICR)] = NRF9_NVMC_REG(0x514), + [reg_index(NRFX_BPROT_BASE)] = NRFX_UNIMPLEMENTED, }; -struct nrf52_ficr_info { +enum nrfx_features { + NRFX_FEATURE_SERIES_51 = 1 << 0, + NRFX_FEATURE_SERIES_52 = 1 << 1, + NRFX_FEATURE_SERIES_91 = 1 << 2, + NRFX_FEATURE_BPROT = 1 << 3, + NRFX_FEATURE_ACL_PROT = 1 << 4, +}; + +struct nrfx_device_id { + uint16_t hwid; + uint32_t part; +}; + +struct nrfx_ficr_info { uint32_t part; uint32_t variant; uint32_t package; uint32_t ram; uint32_t flash; + uint32_t flash_page_size; + uint32_t num_sectors; }; -enum nrf5_features { - NRF5_FEATURE_SERIES_51 = 1 << 0, - NRF5_FEATURE_SERIES_52 = 1 << 1, - NRF5_FEATURE_BPROT = 1 << 2, - NRF5_FEATURE_ACL_PROT = 1 << 3, -}; - -struct nrf5_device_spec { - uint16_t hwid; +struct nrfx_device_spec { + struct nrfx_device_id id; const char *part; const char *variant; const char *build_code; unsigned int flash_size_kb; - enum nrf5_features features; + enum nrfx_features features; }; -struct nrf5_info { +struct nrfx_info { unsigned int refcount; - struct nrf5_bank { - struct nrf5_info *chip; - bool probed; + struct nrfx_bank { + struct nrfx_info *chip; + int probed; } bank[2]; + enum nrfx_family family; + const uint32_t *ficr_registers; + const uint32_t *uicr_registers; + const uint32_t *nvmc_registers; struct target *target; - - /* chip identification stored in nrf5_probe() for use in nrf5_info() */ + /* chip identification stored in nrfx_probe() for use in nrfx_info() */ bool ficr_info_valid; - struct nrf52_ficr_info ficr_info; - const struct nrf5_device_spec *spec; uint16_t hwid; - enum nrf5_features features; - unsigned int flash_size_kb; - unsigned int ram_size_kb; + struct nrfx_ficr_info ficr_info; + const struct nrfx_device_spec *spec; + enum nrfx_features features; + uint32_t flash_size_kb; + uint32_t 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, \ +static inline int reg_read(struct nrfx_info *chip, uint32_t addr, uint32_t *out) +{ + if (addr == NRFX_UNIMPLEMENTED) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + return target_read_u32(chip->target, addr, out); +} + +static inline int reg_write(struct nrfx_info *chip, uint32_t addr, uint32_t in) +{ + if (addr == NRFX_UNIMPLEMENTED) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + return target_write_u32(chip->target, addr, in); +} + +static inline int ficr_read(struct nrfx_info *chip, enum nrfx_ficr_registers r, + uint32_t *out) +{ + return reg_read(chip, chip->ficr_registers[r & REG_INDEX_MASK], out); +} + +static inline int uicr_read(struct nrfx_info *chip, enum nrfx_uicr_registers r, + uint32_t *out) +{ + return reg_read(chip, chip->uicr_registers[r & REG_INDEX_MASK], out); +} + +static inline int uicr_write(struct nrfx_info *chip, enum nrfx_uicr_registers r, + uint32_t in) +{ + return reg_write(chip, chip->uicr_registers[r & REG_INDEX_MASK], in); +} + +static inline int nvmc_read(struct nrfx_info *chip, enum nrfx_nvmc_registers r, + uint32_t *out) +{ + return reg_read(chip, chip->nvmc_registers[r & REG_INDEX_MASK], out); +} + +static inline int nvmc_write(struct nrfx_info *chip, enum nrfx_nvmc_registers r, + uint32_t in) +{ + return reg_write(chip, chip->nvmc_registers[r & REG_INDEX_MASK], in); +} + +static inline int ficr_is_implemented(struct nrfx_info *chip, + enum nrfx_ficr_registers r) +{ + return chip->ficr_registers[r & REG_INDEX_MASK] != NRFX_UNIMPLEMENTED; +} + +static inline int uicr_is_implemented(struct nrfx_info *chip, + enum nrfx_uicr_registers r) +{ + return chip->uicr_registers[r & REG_INDEX_MASK] != NRFX_UNIMPLEMENTED; +} + +#define NRF51_DEVICE_DEF(_id, pt, var, bcode, fsize) \ +{ \ +.id = { .hwid = (_id), .part = 0x ## pt }, \ +.part = # pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +.features = NRFX_FEATURE_SERIES_51, \ } -#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, \ +#define NRF52_DEVICE_DEF(_id, pt, var, bcode, fsize, _features) \ +{ \ +.id = { .hwid = (_id), .part = 0x ## pt }, \ +.part = # pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +.features = NRFX_FEATURE_SERIES_52 | (_features), \ +} + +#define NRF91_DEVICE_DEF(pt, var, bcode, fsize) \ +{ \ +.id = { .hwid = 0xFFFF, .part = 0x ## pt }, \ +.part = # pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +.features = NRFX_FEATURE_SERIES_91, \ } /* The known devices table below is derived from the "nRF5x series @@ -191,121 +521,124 @@ struct nrf5_info { * 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[] = { +static const struct nrfx_device_spec nrfx_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), + 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), + 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), + 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), + 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), + 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), + 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), + 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), + NRF52_DEVICE_DEF(0x0142, 52810, "QFAA", "B0", 192, NRFX_FEATURE_BPROT), + NRF52_DEVICE_DEF(0x0143, 52810, "QCAA", "C0", 192, NRFX_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), + NRF52_DEVICE_DEF(0x00C7, 52832, "QFAA", "B0", 512, NRFX_FEATURE_BPROT), + NRF52_DEVICE_DEF(0x0139, 52832, "QFAA", "E0", 512, NRFX_FEATURE_BPROT), + NRF52_DEVICE_DEF(0x00E3, 52832, "CIAA", "B0", 512, NRFX_FEATURE_BPROT), /* nRF52840 Devices */ - NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT), -#endif + NRF52_DEVICE_DEF(0x0150, 52840, "QIAA", "C0", 1024, NRFX_FEATURE_ACL_PROT), + NRF52_DEVICE_DEF(0x0164, 52840, "0DAA", "CK", 1024, NRFX_FEATURE_ACL_PROT), + + /* nRF91xx Devices */ + NRF91_DEVICE_DEF(9120, "0BAA", "QF", 1024), }; -struct nrf5_device_package { +struct nrfx_device_package { uint32_t package; const char *code; }; /* Newer devices have FICR INFO.PACKAGE. * This table converts its value to two character code */ -static const struct nrf5_device_package nrf5_packages_table[] = { +static const struct nrfx_device_package nrfx_packages_table[] = { { 0x2000, "QF" }, { 0x2001, "CH" }, { 0x2002, "CI" }, { 0x2005, "CK" }, }; -const struct flash_driver nrf5_flash, nrf51_flash; +const struct flash_driver nrf5_flash, nrf51_flash, nrf52_flash, nrf91_flash; -static bool nrf5_bank_is_probed(const struct flash_bank *bank) +static bool nrfx_bank_is_probed(const struct flash_bank *bank) { - struct nrf5_bank *nbank = bank->driver_priv; + struct nrfx_bank *nbank = bank->driver_priv; assert(nbank); - return nbank->probed; + struct nrfx_info *chip = nbank->chip; + assert(chip); + + return chip->bank[bank->bank_number].probed; } -static int nrf5_probe(struct flash_bank *bank); +static int nrfx_auto_probe(struct flash_bank *bank); -static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip) +static int nrfx_get_probed_chip_if_halted(struct flash_bank *bank, struct nrfx_info **chip) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - struct nrf5_bank *nbank = bank->driver_priv; + struct nrfx_bank *nbank = bank->driver_priv; *chip = nbank->chip; - if (nrf5_bank_is_probed(bank)) - return ERROR_OK; - - return nrf5_probe(bank); + return nrfx_auto_probe(bank); } -static int nrf5_wait_for_nvmc(struct nrf5_info *chip) +static int nrfx_wait_for_nvmc(struct nrfx_info *chip) { uint32_t ready; int res; @@ -313,7 +646,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 = nvmc_read(chip, NRFX_NVMC_READY, &ready); if (res != ERROR_OK) { LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)"); return res; @@ -324,18 +657,15 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) keep_alive(); - } while ((timeval_ms()-ts_start) < timeout_ms); + } while ((timeval_ms() - ts_start) < timeout_ms); LOG_DEBUG("Timed out waiting for NVMC_READY"); return ERROR_FLASH_BUSY; } -static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) +static int nrfx_nvmc_erase_enable(struct nrfx_info *chip) { - int res; - res = target_write_u32(chip->target, - NRF5_NVMC_CONFIG, - NRF5_NVMC_CONFIG_EEN); + int res = nvmc_write(chip, NRFX_NVMC_CONFIG, NRFX_NVMC_CONFIG_EEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable erase operation"); @@ -346,19 +676,16 @@ 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(chip); 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_info *chip) { - int res; - res = target_write_u32(chip->target, - NRF5_NVMC_CONFIG, - NRF5_NVMC_CONFIG_WEN); + int res = nvmc_write(chip, NRFX_NVMC_CONFIG, NRFX_NVMC_CONFIG_WEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable write operation"); @@ -369,19 +696,16 @@ 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(chip); 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_info *chip) { - int res; - res = target_write_u32(chip->target, - NRF5_NVMC_CONFIG, - NRF5_NVMC_CONFIG_REN); + int res = nvmc_write(chip, NRFX_NVMC_CONFIG, NRFX_NVMC_CONFIG_REN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable read-only operation"); @@ -391,67 +715,79 @@ 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(chip); if (res != ERROR_OK) LOG_ERROR("Read only enable did not complete"); return res; } -static int nrf5_nvmc_generic_erase(struct nrf5_info *chip, - uint32_t erase_register, uint32_t erase_value) +static int nrfx_nvmc_generic_erase(struct nrfx_info *chip, + uint32_t erase_addr, + enum nrfx_nvmc_registers erase_register, + uint32_t erase_value) { int res; - res = nrf5_nvmc_erase_enable(chip); + res = nrfx_nvmc_erase_enable(chip); if (res != ERROR_OK) goto error; - res = target_write_u32(chip->target, - erase_register, - erase_value); - if (res != ERROR_OK) - goto set_read_only; + if (chip->family != NRFX_FAMILY_91) { + res = nvmc_write(chip, erase_register, erase_value); + if (res != ERROR_OK) + goto set_read_only; + } else { + target_write_u32(chip->target, erase_addr, 0xffffffff); + usleep(100000); + } - res = nrf5_wait_for_nvmc(chip); + res = nrfx_wait_for_nvmc(chip); if (res != ERROR_OK) goto set_read_only; - return nrf5_nvmc_read_only(chip); + return nrfx_nvmc_read_only(chip); set_read_only: - nrf5_nvmc_read_only(chip); + nrfx_nvmc_read_only(chip); error: - LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32, + LOG_ERROR("Failed to erase reg: 0x%08" PRIx32 " val: 0x%08" PRIx32, erase_register, erase_value); return ERROR_FAIL; } -static int nrf5_protect_check_clenr0(struct flash_bank *bank) +static int nrf51_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_bank *nbank = bank->driver_priv; + struct nrfx_info *chip = nbank->chip; assert(chip); - res = target_read_u32(chip->target, NRF51_FICR_CLENR0, - &clenr0); + res = ficr_read(chip, NRFX_FICR_CLENR0, &clenr0); + + if (res == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* CLENR0 not implemented */ + clenr0 = 0xFFFFFFFF; + goto no_clenr0; + } + if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); return res; } if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, - &clenr0); + res = uicr_read(chip, NRFX_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); return res; } } +no_clenr0: for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0; @@ -459,10 +795,10 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank) return ERROR_OK; } -static int nrf5_protect_check_bprot(struct flash_bank *bank) +static int nrfx_protect_check_bprot(struct flash_bank *bank) { - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_bank *nbank = bank->driver_priv; + struct nrfx_info *chip = nbank->chip; assert(chip); @@ -477,7 +813,9 @@ 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 = reg_read(chip, + chip->nvmc_registers[NRFX_BPROT_BASE & REG_INDEX_MASK] + + nrf5_bprot_offsets[n_reg], &bprot_reg); if (res != ERROR_OK) return res; } @@ -486,42 +824,42 @@ static int nrf5_protect_check_bprot(struct flash_bank *bank) return ERROR_OK; } -static int nrf5_protect_check(struct flash_bank *bank) +static int nrfx_protect_check(struct flash_bank *bank) { /* UICR cannot be write protected so just return early */ - if (bank->base == NRF5_UICR_BASE) + if (bank->base == NRF5_UICR_BASE || + bank->base == NRF9_UICR_BASE) return ERROR_OK; - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_bank *nbank = bank->driver_priv; + struct nrfx_info *chip = nbank->chip; assert(chip); - if (chip->features & NRF5_FEATURE_BPROT) - return nrf5_protect_check_bprot(bank); + if (chip->features & NRFX_FEATURE_BPROT) + return nrfx_protect_check_bprot(bank); - if (chip->features & NRF5_FEATURE_SERIES_51) - return nrf5_protect_check_clenr0(bank); + if (chip->features & NRFX_FEATURE_SERIES_51) + return nrf51_protect_check_clenr0(bank); LOG_WARNING("Flash protection of this nRF device is not supported"); return ERROR_FLASH_OPER_UNSUPPORTED; } -static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, +static int nrfx_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; uint32_t clenr0, ppfc; - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; + struct nrfx_bank *nbank = bank->driver_priv; + struct nrfx_info *chip = nbank->chip; 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, - &ppfc); + res = ficr_read(chip, NRFX_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); return res; @@ -532,8 +870,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, - &clenr0); + res = uicr_read(chip, NRFX_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size from UICR"); return res; @@ -544,14 +881,14 @@ static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int fi return ERROR_FAIL; } - res = nrf5_nvmc_write_enable(chip); + res = nrfx_nvmc_write_enable(chip); 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 = uicr_write(chip, NRFX_UICR_CLENR0, clenr0); - int res2 = nrf5_wait_for_nvmc(chip); + int res2 = nrfx_wait_for_nvmc(chip); if (res == ERROR_OK) res = res2; @@ -562,16 +899,16 @@ 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(chip); return res; } -static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, +static int nrfx_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; - struct nrf5_info *chip; + struct nrfx_info *chip; /* UICR cannot be write protected so just bail out early */ if (bank->base == NRF5_UICR_BASE) { @@ -579,18 +916,18 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, return ERROR_FLASH_OPER_UNSUPPORTED; } - res = nrf5_get_probed_chip_if_halted(bank, &chip); + res = nrfx_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; - if (chip->features & NRF5_FEATURE_SERIES_51) - return nrf5_protect_clenr0(bank, set, first, last); + if (chip->features & NRFX_FEATURE_SERIES_51) + return nrfx_protect_clenr0(bank, set, first, last); LOG_ERROR("Flash protection setting is not supported on this nRF5 device"); return ERROR_FLASH_OPER_UNSUPPORTED; } -static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) +static bool nrfx_info_variant_to_str(uint32_t variant, char *bf) { uint8_t b[4]; @@ -605,16 +942,16 @@ static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) return false; } -static const char *nrf5_decode_info_package(uint32_t package) +static const char *nrfx_decode_info_package(uint32_t package) { - for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) { - if (nrf5_packages_table[i].package == package) - return nrf5_packages_table[i].code; + for (size_t i = 0; i < ARRAY_SIZE(nrfx_packages_table); i++) { + if (nrfx_packages_table[i].package == package) + return nrfx_packages_table[i].code; } return "xx"; } -static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size) +static int get_nrfx_chip_type_str(const struct nrfx_info *chip, char *buf, unsigned int buf_size) { int res; if (chip->spec) { @@ -622,10 +959,10 @@ static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsig chip->spec->part, chip->spec->variant, chip->spec->build_code); } else if (chip->ficr_info_valid) { char variant[5]; - nrf5_info_variant_to_str(chip->ficr_info.variant, variant); + nrfx_info_variant_to_str(chip->ficr_info.variant, variant); res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)", chip->ficr_info.part, - nrf5_decode_info_package(chip->ficr_info.package), + nrfx_decode_info_package(chip->ficr_info.package), variant, &variant[2]); } else { res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid); @@ -639,13 +976,13 @@ 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_bank *nbank = bank->driver_priv; + struct nrfx_info *chip = nbank->chip; char chip_type_str[256]; - if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + if (get_nrfx_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM", @@ -653,43 +990,60 @@ static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) return ERROR_OK; } -static int nrf5_read_ficr_info(struct nrf5_info *chip) +static int nrfx_read_ficr_info(struct nrfx_info *chip) { int res; - struct target *target = chip->target; chip->ficr_info_valid = false; - res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part); + if (!ficr_is_implemented(chip, NRFX_FICR_INFO_PART)) { + LOG_INFO("FICR INFO.PART register not supported"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + res = ficr_read(chip, NRFX_FICR_INFO_PART, &chip->ficr_info.part); if (res != ERROR_OK) { - LOG_DEBUG("Couldn't read FICR INFO.PART register"); + LOG_INFO("Couldn't read FICR INFO.PART register"); return res; } uint32_t series = chip->ficr_info.part & 0xfffff000; switch (series) { case 0x51000: - chip->features = NRF5_FEATURE_SERIES_51; + chip->features = NRFX_FEATURE_SERIES_51; break; case 0x52000: - chip->features = NRF5_FEATURE_SERIES_52; + chip->features = NRFX_FEATURE_SERIES_52; switch (chip->ficr_info.part) { case 0x52810: case 0x52832: - chip->features |= NRF5_FEATURE_BPROT; + chip->features |= NRFX_FEATURE_BPROT; break; case 0x52840: - chip->features |= NRF5_FEATURE_ACL_PROT; + chip->features |= NRFX_FEATURE_ACL_PROT; break; } break; + case 0x9000: + res = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + switch (chip->ficr_info.part) { + case 0x9120: + case 0x9160: + chip->features |= NRFX_FEATURE_SERIES_91; + res = ERROR_OK; + break; + } + if (res == ERROR_OK) + break; + /* fallthrough */ + default: - LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08" - PRIx32, chip->ficr_info.part); + LOG_INFO("FICR INFO likely not implemented. Invalid PART value (%x) 0x%08" + PRIx32, series, chip->ficr_info.part); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -699,19 +1053,19 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip) * 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 = ficr_read(chip, NRFX_FICR_INFO_VARIANT, &chip->ficr_info.variant); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package); + res = ficr_read(chip, NRFX_FICR_INFO_PACKAGE, &chip->ficr_info.package); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram); + res = ficr_read(chip, NRFX_FICR_INFO_RAM, &chip->ficr_info.ram); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash); + res = ficr_read(chip, NRFX_FICR_INFO_FLASH, &chip->ficr_info.flash); if (res != ERROR_OK) return res; @@ -719,14 +1073,14 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip) return ERROR_OK; } -static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) +static int nrfx_get_ram_size(struct nrfx_info *chip, uint32_t *ram_size) { int res; *ram_size = 0; uint32_t numramblock; - res = target_read_u32(target, NRF51_FICR_NUMRAMBLOCK, &numramblock); + res = ficr_read(chip, NRFX_FICR_NUMRAMBLOCK, &numramblock); if (res != ERROR_OK) { LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); return res; @@ -739,7 +1093,7 @@ static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) for (unsigned int i = 0; i < numramblock; i++) { uint32_t sizeramblock; - res = target_read_u32(target, NRF51_FICR_SIZERAMBLOCK0 + sizeof(uint32_t)*i, &sizeramblock); + res = ficr_read(chip, NRFX_FICR_SIZERAMBLOCK0 + sizeof(uint32_t) * i, &sizeramblock); if (res != ERROR_OK) { LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); return res; @@ -752,77 +1106,138 @@ 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_set_registers(struct nrfx_info *chip, enum nrfx_family family) +{ + chip->family = family; + switch (chip->family) { + case NRFX_FAMILY_51: + LOG_DEBUG("Select 51 family"); + /* fallthrough */ + case NRFX_FAMILY_5X: + chip->ficr_registers = nrf51_ficr_registers; + chip->uicr_registers = nrf51_uicr_registers; + chip->nvmc_registers = nrf5_nvmc_registers; + break; + case NRFX_FAMILY_52: + chip->ficr_registers = nrf52_ficr_registers; + chip->uicr_registers = nrf52_uicr_registers; + chip->nvmc_registers = nrf5_nvmc_registers; + LOG_DEBUG("Select 52 family"); + break; + case NRFX_FAMILY_91: + chip->ficr_registers = nrf91_ficr_registers; + chip->uicr_registers = nrf91_uicr_registers; + chip->nvmc_registers = nrf91_nvmc_registers; + LOG_DEBUG("Select 91 family"); + break; + default: + LOG_ERROR("Unsupported family %d\n", chip->family); + return ERROR_FAIL; + } + return ERROR_OK; +} + +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_bank *nbank = bank->driver_priv; + struct nrfx_info *chip = nbank->chip; + enum nrfx_family old_family = chip->family; 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; + chip->features = 0; + if (ficr_is_implemented(chip, NRFX_FICR_CONFIGID)) { + res = ficr_read(chip, NRFX_FICR_CONFIGID, &configid); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read CONFIGID register"); + return res; + } - /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ - chip->features = NRF5_FEATURE_SERIES_51; + /* HWID is stored in the lower two bytes of the CONFIGID register */ + chip->hwid = configid & 0xFFFF; + } /* 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); + (void)nrfx_read_ficr_info(chip); 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]; + for (size_t i = 0; i < ARRAY_SIZE(nrfx_known_devices_table); i++) { + if (chip->hwid == nrfx_known_devices_table[i].id.hwid) { + chip->spec = &nrfx_known_devices_table[i]; chip->features = chip->spec->features; break; } } - if (chip->spec && chip->ficr_info_valid) { + if (!chip->spec && chip->ficr_info_valid) { + /* In case if CONFIGID is not supported */ + for (size_t i = 0; i < ARRAY_SIZE(nrfx_known_devices_table); i++) { + if (chip->ficr_info.part == nrfx_known_devices_table[i].id.part && + nrfx_known_devices_table[i].id.hwid == 0xFFFF) { + chip->spec = &nrfx_known_devices_table[i]; + chip->features = chip->spec->features; + break; + } + } + } + if (chip->features & NRFX_FEATURE_SERIES_51) + chip->family = NRFX_FAMILY_51; + else if (chip->features & NRFX_FEATURE_SERIES_52) + chip->family = NRFX_FAMILY_52; + else if (chip->features & NRFX_FEATURE_SERIES_91) + chip->family = NRFX_FAMILY_91; + else + chip->family = old_family; + + /* Update registers definition based on family */ + res = nrfx_set_registers(chip, chip->family); + if (res != ERROR_OK) + return res; + + if (!chip->spec) { + LOG_ERROR("Probing failed: HWID 0x%04" PRIx32 " FICR INFO.PART %" PRIx32, chip->hwid, chip->ficr_info.part); + return ERROR_FAIL; + } + + if (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); } + LOG_DEBUG("Probed: 0x%06x 0x%06x", chip->spec->id.hwid, chip->spec->id.part); + if (chip->ficr_info_valid) { chip->ram_size_kb = chip->ficr_info.ram; } else { uint32_t ram_size; - nrf5_get_ram_size(target, &ram_size); + nrfx_get_ram_size(chip, &ram_size); chip->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); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code page size"); - return res; - } + if (bank->base == NRFX_FLASH_BASE) { + /* The value stored in NRFX_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + res = ficr_read(chip, NRFX_FICR_CODEPAGESIZE, &chip->ficr_info.flash_page_size); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code page size"); + return res; + } - /* 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); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code memory size"); - return res; + /* Note the register name is misleading, + * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ + res = ficr_read(chip, NRFX_FICR_CODESIZE, &chip->ficr_info.num_sectors); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code memory size"); + return res; + } + chip->flash_size_kb = chip->ficr_info.num_sectors * chip->ficr_info.flash_page_size / 1024; } - chip->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 (get_nrfx_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); LOG_INFO("%s%s %ukB Flash, %ukB RAM", @@ -834,27 +1249,40 @@ static int nrf5_probe(struct flash_bank *bank) free(bank->sectors); - if (bank->base == NRF5_FLASH_BASE) { + if (bank->base == NRFX_FLASH_BASE) { /* 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"); - bank->num_sectors = num_sectors; - bank->size = num_sectors * flash_page_size; + bank->num_sectors = chip->ficr_info.num_sectors; + bank->size = bank->num_sectors * chip->ficr_info.flash_page_size; - bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + bank->sectors = alloc_block_array(0, chip->ficr_info.flash_page_size, chip->ficr_info.num_sectors); if (!bank->sectors) return ERROR_FAIL; + /* Fill out the sector information: all NRFX sectors are the same size and + * there is always a fixed number of them. */ + for (unsigned int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].size = chip->ficr_info.flash_page_size; + bank->sectors[i].offset = i * chip->ficr_info.flash_page_size; + + /* mark as unknown */ + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = -1; + } + + nrfx_protect_check(bank); + chip->bank[0].probed = true; } else { bank->num_sectors = 1; - bank->size = flash_page_size; + bank->size = NRFX_UICR_SIZE; - bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + bank->sectors = alloc_block_array(0, bank->size, 1); if (!bank->sectors) return ERROR_FAIL; @@ -866,35 +1294,39 @@ static int nrf5_probe(struct flash_bank *bank) 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)) + if(nrfx_bank_is_probed(bank)) 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_info *chip) { LOG_DEBUG("Erasing all non-volatile memory"); - return nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEALL, + return nrfx_nvmc_generic_erase(chip, + 0, + NRFX_NVMC_ERASEALL, 0x00000001); } -static int nrf5_erase_page(struct flash_bank *bank, - struct nrf5_info *chip, - struct flash_sector *sector) +static int nrfx_erase_page(struct flash_bank *bank, + struct nrfx_info *chip, + struct flash_sector *sector) { int res; + LOG_DEBUG("Erasing page at 0x%" PRIx32, sector->offset); - LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset); + /* TODO: Inspect #5348 further whether the removal is still valid*/ + if (sector->is_protected) { + LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset); + return ERROR_FAIL; + } if (bank->base == NRF5_UICR_BASE) { - if (chip->features & NRF5_FEATURE_SERIES_51) { + if (chip->features & NRFX_FEATURE_SERIES_51) { uint32_t ppfc; - res = target_read_u32(chip->target, NRF51_FICR_PPFC, - &ppfc); + res = ficr_read(chip, NRFX_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); return res; @@ -912,22 +1344,24 @@ static int nrf5_erase_page(struct flash_bank *bank, } } - res = nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEUICR, - 0x00000001); + res = nrfx_nvmc_generic_erase(chip, + 0, + NRFX_NVMC_ERASEUICR, + 0x00000001); } else { - res = nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEPAGE, - sector->offset); + res = nrfx_nvmc_generic_erase(chip, + sector->offset, + NRFX_NVMC_ERASEPAGE, + sector->offset); } 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_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; @@ -937,15 +1371,15 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - static const uint8_t nrf5_flash_write_code[] = { + static const uint8_t nrfx_flash_write_code[] = { #include "../../../contrib/loaders/flash/nrf5/nrf5.inc" }; - LOG_DEBUG("Writing buffer to flash address=0x%"PRIx32" bytes=0x%"PRIx32, address, bytes); - assert(bytes % 4 == 0); + LOG_DEBUG("Writing buffer to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, address, bytes); + assert(IS_ALIGNED(bytes, 4)); /* allocate working area with flash programming code */ - if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code), + if (target_alloc_working_area(target, sizeof(nrfx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, falling back to slow memory writes"); @@ -954,7 +1388,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(chip); if (retval != ERROR_OK) return retval; @@ -966,8 +1400,8 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u } retval = target_write_buffer(target, write_algorithm->address, - sizeof(nrf5_flash_write_code), - nrf5_flash_write_code); + sizeof(nrfx_flash_write_code), + nrfx_flash_write_code); if (retval != ERROR_OK) return retval; @@ -1001,11 +1435,11 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE); buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER); - retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4, + retval = target_run_flash_async_algorithm(target, buffer, bytes / 4, 4, 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, - write_algorithm->address, write_algorithm->address + sizeof(nrf5_flash_write_code) - 2, + write_algorithm->address, write_algorithm->address + sizeof(nrfx_flash_write_code) - 2, &armv7m_info); target_free_working_area(target, source); @@ -1021,15 +1455,17 @@ 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, - uint32_t offset, uint32_t count) +static int nrfx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) { - struct nrf5_info *chip; - - int res = nrf5_get_probed_chip_if_halted(bank, &chip); + struct nrfx_info *chip; + int res = nrfx_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; + if (!chip) + return ERROR_FAIL; + assert(offset % 4 == 0); assert(count % 4 == 0); @@ -1041,9 +1477,9 @@ 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 (chip->features & NRFX_FEATURE_SERIES_51) { - res = nrf5_protect_check_clenr0(bank); + res = nrf51_protect_check_clenr0(bank); if (res != ERROR_OK) return res; @@ -1061,29 +1497,31 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, } } - res = nrf5_nvmc_write_enable(chip); + res = nrfx_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; - res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count); + if (chip->family != NRFX_FAMILY_91) + res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count); + else + res = target_write_buffer(chip->target, bank->base + offset, count, buffer); if (res != ERROR_OK) goto error; - - return nrf5_nvmc_read_only(chip); + return nrfx_nvmc_read_only(chip); error: - nrf5_nvmc_read_only(chip); - LOG_ERROR("Failed to write to nrf5 flash"); + nrfx_nvmc_read_only(chip); + LOG_ERROR("Failed to write to 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_info *chip; - res = nrf5_get_probed_chip_if_halted(bank, &chip); + res = nrfx_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -1093,23 +1531,21 @@ 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) { - - res = nrf5_protect_check_clenr0(bank); + if (chip->features & NRFX_FEATURE_SERIES_51) { + res = nrf51_protect_check_clenr0(bank); if (res != ERROR_OK) return res; } /* 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 (chip->features & NRFX_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, chip, &bank->sectors[s]); if (res != ERROR_OK) { LOG_ERROR("Error erasing sector %d", s); return res; @@ -1119,10 +1555,10 @@ 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; + struct nrfx_bank *nbank = bank->driver_priv; + struct nrfx_info *chip = nbank->chip; if (!chip) return; @@ -1133,19 +1569,21 @@ static void nrf5_free_driver_priv(struct flash_bank *bank) } } -static struct nrf5_info *nrf5_get_chip(struct target *target) +static struct nrfx_info *nrfx_get_chip(struct target *target) { struct flash_bank *bank_iter; - /* iterate over nrf5 banks of same target */ + /* iterate over nrf 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) + if (bank_iter->driver != &nrf5_flash && + bank_iter->driver != &nrf51_flash && + bank_iter->driver != &nrf91_flash) continue; if (bank_iter->target != target) continue; - struct nrf5_bank *nbank = bank_iter->driver_priv; + struct nrfx_bank *nbank = bank_iter->driver_priv; if (!nbank) continue; @@ -1155,21 +1593,23 @@ static struct nrf5_info *nrf5_get_chip(struct target *target) return NULL; } -FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) +static int nrfx_flash_bank_command(struct flash_bank *bank, enum nrfx_family family) { - struct nrf5_info *chip; - struct nrf5_bank *nbank = NULL; + int res; + struct nrfx_info *chip; + struct nrfx_bank *nbank = NULL; switch (bank->base) { - case NRF5_FLASH_BASE: + case NRFX_FLASH_BASE: case NRF5_UICR_BASE: + case NRF9_UICR_BASE: break; default: LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); return ERROR_FAIL; } - chip = nrf5_get_chip(bank->target); + chip = nrfx_get_chip(bank->target); if (!chip) { /* Create a new chip */ chip = calloc(1, sizeof(*chip)); @@ -1177,16 +1617,23 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) return ERROR_FAIL; chip->target = bank->target; + res = nrfx_set_registers(chip, family); + if (res != ERROR_OK) { + free(chip); + return res; + } } switch (bank->base) { - case NRF5_FLASH_BASE: + case NRFX_FLASH_BASE: nbank = &chip->bank[0]; break; case NRF5_UICR_BASE: + case NRF9_UICR_BASE: nbank = &chip->bank[1]; break; } + assert(nbank); chip->refcount++; @@ -1194,32 +1641,50 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) nbank->probed = false; bank->driver_priv = nbank; bank->write_start_alignment = bank->write_end_alignment = 4; - return ERROR_OK; } -COMMAND_HANDLER(nrf5_handle_mass_erase_command) +FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) +{ + return nrfx_flash_bank_command(bank, NRFX_FAMILY_5X); +} + +FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) +{ + return nrfx_flash_bank_command(bank, NRFX_FAMILY_51); +} + +FLASH_BANK_COMMAND_HANDLER(nrf52_flash_bank_command) +{ + return nrfx_flash_bank_command(bank, NRFX_FAMILY_52); +} + +FLASH_BANK_COMMAND_HANDLER(nrf91_flash_bank_command) +{ + return nrfx_flash_bank_command(bank, NRFX_FAMILY_91); +} + +COMMAND_HANDLER(nrfx_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, NRF5_FLASH_BASE, true, &bank); + res = get_flash_bank_by_addr(target, NRFX_FLASH_BASE, true, &bank); if (res != ERROR_OK) return res; assert(bank); - struct nrf5_info *chip; + struct nrfx_info *chip; - res = nrf5_get_probed_chip_if_halted(bank, &chip); + res = nrfx_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; - if (chip->features & NRF5_FEATURE_SERIES_51) { + if (chip->features & NRFX_FEATURE_SERIES_51) { uint32_t ppfc; - res = target_read_u32(target, NRF51_FICR_PPFC, - &ppfc); + res = ficr_read(chip, NRFX_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); return res; @@ -1232,10 +1697,10 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) } } - res = nrf5_erase_all(chip); + res = nrfx_erase_all(chip); if (res == ERROR_OK) { LOG_INFO("Mass erase completed."); - if (chip->features & NRF5_FEATURE_SERIES_51) + if (chip->features & NRFX_FEATURE_SERIES_51) LOG_INFO("A reset or power cycle is required if the flash was protected before."); } else { @@ -1245,149 +1710,208 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) return res; } -COMMAND_HANDLER(nrf5_handle_info_command) +COMMAND_HANDLER(nrfx_handle_info_command) { int res; struct flash_bank *bank = NULL; struct target *target = get_current_target(CMD_CTX); - res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); + struct nrfx_info *chip; + uint32_t ficr[NRFX_FICR_NREGS]; + uint32_t uicr[NRFX_UICR_NREGS]; + + res = get_flash_bank_by_addr(target, NRFX_FLASH_BASE, true, &bank); if (res != ERROR_OK) return res; assert(bank); - struct nrf5_info *chip; - - res = nrf5_get_probed_chip_if_halted(bank, &chip); + res = nrfx_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; - static struct { - const uint32_t address; - uint32_t value; - } ficr[] = { - { .address = NRF5_FICR_CODEPAGESIZE }, - { .address = NRF5_FICR_CODESIZE }, - { .address = NRF51_FICR_CLENR0 }, - { .address = NRF51_FICR_PPFC }, - { .address = NRF51_FICR_NUMRAMBLOCK }, - { .address = NRF51_FICR_SIZERAMBLOCK0 }, - { .address = NRF51_FICR_SIZERAMBLOCK1 }, - { .address = NRF51_FICR_SIZERAMBLOCK2 }, - { .address = NRF51_FICR_SIZERAMBLOCK3 }, - { .address = NRF5_FICR_CONFIGID }, - { .address = NRF5_FICR_DEVICEID0 }, - { .address = NRF5_FICR_DEVICEID1 }, - { .address = NRF5_FICR_ER0 }, - { .address = NRF5_FICR_ER1 }, - { .address = NRF5_FICR_ER2 }, - { .address = NRF5_FICR_ER3 }, - { .address = NRF5_FICR_IR0 }, - { .address = NRF5_FICR_IR1 }, - { .address = NRF5_FICR_IR2 }, - { .address = NRF5_FICR_IR3 }, - { .address = NRF5_FICR_DEVICEADDRTYPE }, - { .address = NRF5_FICR_DEVICEADDR0 }, - { .address = NRF5_FICR_DEVICEADDR1 }, - { .address = NRF51_FICR_OVERRIDEN }, - { .address = NRF51_FICR_NRF_1MBIT0 }, - { .address = NRF51_FICR_NRF_1MBIT1 }, - { .address = NRF51_FICR_NRF_1MBIT2 }, - { .address = NRF51_FICR_NRF_1MBIT3 }, - { .address = NRF51_FICR_NRF_1MBIT4 }, - { .address = NRF51_FICR_BLE_1MBIT0 }, - { .address = NRF51_FICR_BLE_1MBIT1 }, - { .address = NRF51_FICR_BLE_1MBIT2 }, - { .address = NRF51_FICR_BLE_1MBIT3 }, - { .address = NRF51_FICR_BLE_1MBIT4 }, - }, uicr[] = { - { .address = NRF51_UICR_CLENR0, }, - { .address = NRF51_UICR_RBPCONF }, - { .address = NRF51_UICR_XTALFREQ }, - { .address = NRF51_UICR_FWID }, - }; - - for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { - res = target_read_u32(chip->target, ficr[i].address, - &ficr[i].value); + for (size_t i = 0; i < NRFX_FICR_NREGS; i++) { + res = ficr_read(chip, i, &ficr[i]); + if (res == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + /* Register is not implemented, go on */ + continue; if (res != ERROR_OK) { - LOG_ERROR("Couldn't read %" PRIx32, ficr[i].address); + LOG_ERROR("Couldn't read %" PRIx32, chip->ficr_registers[i]); return res; } } - for (size_t i = 0; i < ARRAY_SIZE(uicr); i++) { - res = target_read_u32(chip->target, uicr[i].address, - &uicr[i].value); + for (size_t i = 0; i < NRFX_UICR_NREGS; i++) { + res = uicr_read(chip, i, &uicr[i]); + if (res == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + /* Register is not implemented, go on */ + continue; if (res != ERROR_OK) { - LOG_ERROR("Couldn't read %" PRIx32, uicr[i].address); + LOG_ERROR("Couldn't read %" PRIx32, chip->uicr_registers[i]); return res; } } - command_print(CMD, - "\n[factory information control block]\n\n" - "code page size: %"PRIu32"B\n" - "code memory size: %"PRIu32"kB\n" - "code region 0 size: %"PRIu32"kB\n" - "pre-programmed code: %s\n" - "number of ram blocks: %"PRIu32"\n" - "ram block 0 size: %"PRIu32"B\n" - "ram block 1 size: %"PRIu32"B\n" - "ram block 2 size: %"PRIu32"B\n" - "ram block 3 size: %"PRIu32 "B\n" - "config id: %" PRIx32 "\n" - "device id: 0x%"PRIx32"%08"PRIx32"\n" - "encryption root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n" - "identity root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n" - "device address type: 0x%"PRIx32"\n" - "device address: 0x%"PRIx32"%08"PRIx32"\n" - "override enable: %"PRIx32"\n" - "NRF_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n" - "BLE_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n" - "\n[user information control block]\n\n" - "code region 0 size: %"PRIu32"kB\n" - "read back protection configuration: %"PRIx32"\n" - "reset value for XTALFREQ: %"PRIx32"\n" - "firmware id: 0x%04"PRIx32, - ficr[0].value, - (ficr[1].value * ficr[0].value) / 1024, - (ficr[2].value == 0xFFFFFFFF) ? 0 : ficr[2].value / 1024, - ((ficr[3].value & 0xFF) == 0x00) ? "present" : "not present", - ficr[4].value, - ficr[5].value, - (ficr[6].value == 0xFFFFFFFF) ? 0 : ficr[6].value, - (ficr[7].value == 0xFFFFFFFF) ? 0 : ficr[7].value, - (ficr[8].value == 0xFFFFFFFF) ? 0 : ficr[8].value, - ficr[9].value, - ficr[10].value, ficr[11].value, - ficr[12].value, ficr[13].value, ficr[14].value, ficr[15].value, - ficr[16].value, ficr[17].value, ficr[18].value, ficr[19].value, - ficr[20].value, - ficr[21].value, ficr[22].value, - ficr[23].value, - ficr[24].value, ficr[25].value, ficr[26].value, ficr[27].value, ficr[28].value, - ficr[29].value, ficr[30].value, ficr[31].value, ficr[32].value, ficr[33].value, - (uicr[0].value == 0xFFFFFFFF) ? 0 : uicr[0].value / 1024, - uicr[1].value & 0xFFFF, - uicr[2].value & 0xFF, - uicr[3].value & 0xFFFF); - + command_print(CMD, "\n[factory information control block]\n"); + if (ficr_is_implemented(chip, NRFX_FICR_INFO_PART)) + command_print(CMD, "part: %" PRIx32, + ficr[reg_index(NRFX_FICR_INFO_PART)]); + if (ficr_is_implemented(chip, NRFX_FICR_INFO_VARIANT)) { + union { + uint32_t ul; + char str[5]; + } v; + v.str[4] = 0; + v.ul = ficr[reg_index(NRFX_FICR_INFO_VARIANT)]; + command_print(CMD, "variant: %s", v.str); + } + if (ficr_is_implemented(chip, NRFX_FICR_INFO_PACKAGE)) + command_print(CMD, "package: %s", + nrfx_decode_info_package(ficr[reg_index(NRFX_FICR_INFO_PACKAGE)])); + if (ficr_is_implemented(chip, NRFX_FICR_INFO_RAM)) + command_print(CMD, "total RAM: %uKB", + ficr[reg_index(NRFX_FICR_INFO_RAM)]); + if (ficr_is_implemented(chip, NRFX_FICR_CODEPAGESIZE)) { + command_print(CMD, "code page size: %" PRIu32 "B", + ficr[reg_index(NRFX_FICR_CODEPAGESIZE)]); + if (ficr_is_implemented(chip, NRFX_FICR_CODESIZE)) + command_print(CMD, "code memory size: %" PRIu32 "KB", + (ficr[reg_index(NRFX_FICR_CODEPAGESIZE)] * + ficr[reg_index(NRFX_FICR_CODESIZE)]) + >> 10); + } else if (ficr_is_implemented(chip, NRFX_FICR_INFO_FLASH)) + command_print(CMD, "code memory size: %uKB", + ficr[reg_index(NRFX_FICR_INFO_FLASH)]); + if (ficr_is_implemented(chip, NRFX_FICR_CLENR0)) + command_print(CMD, "code region 0 size: %" PRIu32 "kB", + (ficr[reg_index(NRFX_FICR_CLENR0)] == + 0xFFFFFFFF) ? 0 : + ficr[reg_index(NRFX_FICR_CLENR0)] >> 10); + if (ficr_is_implemented(chip, NRFX_FICR_PPFC)) + command_print(CMD, "pre-programmed code: %s", + ((ficr[reg_index(NRFX_FICR_PPFC)] & 0xFF) == + 0x00) ? + "present" : "not present"); + if (ficr_is_implemented(chip, NRFX_FICR_NUMRAMBLOCK)) + command_print(CMD, "number of ram blocks: %" PRIu32, + ficr[reg_index(NRFX_FICR_NUMRAMBLOCK)]); + if (ficr_is_implemented(chip, NRFX_FICR_SIZERAMBLOCK0)) + command_print(CMD, "ram block 0 size: %" PRIu32 "B", + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK0)] == + 0xFFFFFFFF ? 0 : + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK0)]); + if (ficr_is_implemented(chip, NRFX_FICR_SIZERAMBLOCK1)) + command_print(CMD, "ram block 1 size: %" PRIu32 "B", + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK1)] == + 0xFFFFFFFF ? 0 : + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK1)]); + if (ficr_is_implemented(chip, NRFX_FICR_SIZERAMBLOCK2)) + command_print(CMD, "ram block 2 size: %" PRIu32 "B", + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK2)] == + 0xFFFFFFFF ? 0 : + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK2)]); + if (ficr_is_implemented(chip, NRFX_FICR_SIZERAMBLOCK3)) + command_print(CMD, "ram block 3 size: %" PRIu32 "B", + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK3)] == + 0xFFFFFFFF ? 0 : + ficr[reg_index(NRFX_FICR_SIZERAMBLOCK3)]); + if (ficr_is_implemented(chip, NRFX_FICR_CONFIGID)) + command_print(CMD, "config id: %" PRIx32, + ficr[reg_index(NRFX_FICR_CONFIGID)] & 0xFFFF); + if (ficr_is_implemented(chip, NRFX_FICR_DEVICEID0) && + ficr_is_implemented(chip, NRFX_FICR_DEVICEID1)) + command_print(CMD, "device id: 0x%" PRIx32 "%08" PRIx32, + ficr[reg_index(NRFX_FICR_DEVICEID0)], + ficr[reg_index(NRFX_FICR_DEVICEID1)]); + if (ficr_is_implemented(chip, NRFX_FICR_ER0) && + ficr_is_implemented(chip, NRFX_FICR_ER1) && + ficr_is_implemented(chip, NRFX_FICR_ER2) && + ficr_is_implemented(chip, NRFX_FICR_ER3)) + command_print(CMD, "encryption root: 0x%08" PRIx32 "%08" PRIx32 "%08" PRIx32 "%08" PRIx32, + ficr[reg_index(NRFX_FICR_ER0)], + ficr[reg_index(NRFX_FICR_ER1)], + ficr[reg_index(NRFX_FICR_ER2)], + ficr[reg_index(NRFX_FICR_ER3)]); + if (ficr_is_implemented(chip, NRFX_FICR_IR0) && + ficr_is_implemented(chip, NRFX_FICR_IR1) && + ficr_is_implemented(chip, NRFX_FICR_IR2) && + ficr_is_implemented(chip, NRFX_FICR_IR3)) + command_print(CMD, "identity root: 0x%08" PRIx32 "%08" PRIx32 "%08" PRIx32 "%08" PRIx32, + ficr[reg_index(NRFX_FICR_IR0)], + ficr[reg_index(NRFX_FICR_IR1)], + ficr[reg_index(NRFX_FICR_IR2)], + ficr[reg_index(NRFX_FICR_IR3)]); + if (ficr_is_implemented(chip, NRFX_FICR_DEVICEADDRTYPE)) + command_print(CMD, "device address type: 0x%" PRIx32, + ficr[reg_index(NRFX_FICR_DEVICEADDRTYPE)]); + if (ficr_is_implemented(chip, NRFX_FICR_DEVICEADDR0) && + ficr_is_implemented(chip, NRFX_FICR_DEVICEADDR1)) + command_print(CMD, "device address: 0x%" PRIx32 "%08" PRIx32, + ficr[reg_index(NRFX_FICR_DEVICEADDR0)], + ficr[reg_index(NRFX_FICR_DEVICEADDR1)]); + if (ficr_is_implemented(chip, NRFX_FICR_OVERRIDEN)) + command_print(CMD, "override enable: %" PRIx32, + ficr[reg_index(NRFX_FICR_OVERRIDEN)]); + if (ficr_is_implemented(chip, NRFX_FICR_NRF_1MBIT0) && + ficr_is_implemented(chip, NRFX_FICR_NRF_1MBIT1) && + ficr_is_implemented(chip, NRFX_FICR_NRF_1MBIT2) && + ficr_is_implemented(chip, NRFX_FICR_NRF_1MBIT3) && + ficr_is_implemented(chip, NRFX_FICR_NRF_1MBIT4)) + command_print(CMD, "NRF_1MBIT values: %" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx32, + ficr[reg_index(NRFX_FICR_NRF_1MBIT0)], + ficr[reg_index(NRFX_FICR_NRF_1MBIT1)], + ficr[reg_index(NRFX_FICR_NRF_1MBIT2)], + ficr[reg_index(NRFX_FICR_NRF_1MBIT3)], + ficr[reg_index(NRFX_FICR_NRF_1MBIT4)]); + if (ficr_is_implemented(chip, NRFX_FICR_BLE_1MBIT0) && + ficr_is_implemented(chip, NRFX_FICR_BLE_1MBIT1) && + ficr_is_implemented(chip, NRFX_FICR_BLE_1MBIT2) && + ficr_is_implemented(chip, NRFX_FICR_BLE_1MBIT3) && + ficr_is_implemented(chip, NRFX_FICR_BLE_1MBIT4)) + command_print(CMD, "BLE_1MBIT values: %" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx32, + ficr[reg_index(NRFX_FICR_BLE_1MBIT0)], + ficr[reg_index(NRFX_FICR_BLE_1MBIT1)], + ficr[reg_index(NRFX_FICR_BLE_1MBIT2)], + ficr[reg_index(NRFX_FICR_BLE_1MBIT3)], + ficr[reg_index(NRFX_FICR_BLE_1MBIT4)]); + + command_print(CMD, "\n[user information control block]\n"); + if (uicr_is_implemented(chip, NRFX_UICR_CLENR0)) + command_print(CMD, "code region 0 size: %" PRIu32 "kB", + uicr[reg_index(NRFX_UICR_CLENR0)] == 0xFFFFFFFF ? + 0 : uicr[reg_index(NRFX_UICR_CLENR0)]); + if (uicr_is_implemented(chip, NRFX_UICR_RBPCONF)) + command_print(CMD, "read back protection configuration: %" PRIx32, + uicr[reg_index(NRFX_UICR_RBPCONF)] & 0xFFFF); + if (uicr_is_implemented(chip, NRFX_UICR_RBPCONF)) + command_print(CMD, "reset value for XTALFREQ: %" PRIx32, + uicr[reg_index(NRFX_UICR_RBPCONF)] & 0xFFFF); + if (uicr_is_implemented(chip, NRFX_UICR_FWID)) + command_print(CMD, "firmware id: 0x%04" PRIx32, + uicr[reg_index(NRFX_UICR_FWID)] & 0xFFFF); + if (uicr_is_implemented(chip, NRFX_UICR_APPROTECT)) + command_print(CMD, "APPROTECT: %" PRIx32, + uicr[reg_index(NRFX_UICR_APPROTECT)]); + if (uicr_is_implemented(chip, NRFX_UICR_SECUREAPPROTECT)) + command_print(CMD, "SECUREAPPROTECT: %" PRIx32, + uicr[reg_index(NRFX_UICR_SECUREAPPROTECT)]); + if (uicr_is_implemented(chip, NRFX_UICR_ERASEPROTECT)) + command_print(CMD, "ERASEPROTECT: %" PRIx32, + uicr[reg_index(NRFX_UICR_ERASEPROTECT)]); return ERROR_OK; } -static const struct command_registration nrf5_exec_command_handlers[] = { +static const struct command_registration nrfx_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.", .usage = "", }, { .name = "info", - .handler = nrf5_handle_info_command, + .handler = nrfx_handle_info_command, .mode = COMMAND_EXEC, .help = "Show FICR and UICR info.", .usage = "", @@ -1401,14 +1925,25 @@ static const struct command_registration nrf5_command_handlers[] = { .mode = COMMAND_ANY, .help = "nrf5 flash command group", .usage = "", - .chain = nrf5_exec_command_handlers, + .chain = nrfx_exec_command_handlers, }, { .name = "nrf51", .mode = COMMAND_ANY, .help = "nrf51 flash command group", .usage = "", - .chain = nrf5_exec_command_handlers, + .chain = nrfx_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration nrf91_command_handlers[] = { + { + .name = "nrf91", + .mode = COMMAND_ANY, + .help = "nrf91 flash command group", + .usage = "", + .chain = nrfx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; @@ -1417,16 +1952,16 @@ 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, - .protect = nrf5_protect, - .write = nrf5_write, + .info = nrfx_info, + .erase = nrfx_erase, + .protect = nrfx_protect, + .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, + .protect_check = nrfx_protect_check, + .free_driver_priv = nrfx_free_driver_priv, }; /* We need to retain the flash-driver name as well as the commands @@ -1434,15 +1969,47 @@ const struct flash_driver nrf5_flash = { 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, - .protect = nrf5_protect, - .write = nrf5_write, + .flash_bank_command = nrf51_flash_bank_command, + .info = nrfx_info, + .erase = nrfx_erase, + .protect = nrfx_protect, + .write = nrfx_write, + .read = default_flash_read, + .probe = nrfx_probe, + .auto_probe = nrfx_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = nrfx_protect_check, + .free_driver_priv = nrfx_free_driver_priv, +}; + +const struct flash_driver nrf52_flash = { + .name = "nrf52", + .commands = nrf5_command_handlers, + .flash_bank_command = nrf52_flash_bank_command, + .info = nrfx_info, + .erase = nrfx_erase, + .protect = nrfx_protect, + .write = nrfx_write, + .read = default_flash_read, + .probe = nrfx_probe, + .auto_probe = nrfx_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = nrfx_protect_check, + .free_driver_priv = nrfx_free_driver_priv, +}; + +const struct flash_driver nrf91_flash = { + .name = "nrf91", + .commands = nrf91_command_handlers, + .flash_bank_command = nrf91_flash_bank_command, + .info = nrfx_info, + .erase = nrfx_erase, + .protect = nrfx_protect, + .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, + .protect_check = nrfx_protect_check, + .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..c42bc54b29 --- /dev/null +++ b/tcl/target/nrf91.cfg @@ -0,0 +1,46 @@ +# 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] } { + 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 + +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..2850bfb41c --- /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 packge: '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 0 + +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 recieved" + 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 + nrf91_mfw_write_memory 0x500038A8 0x0 + + # 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..fe2abd74ff --- /dev/null +++ b/tcl/target/nrf91_mfw_utils.cfg @@ -0,0 +1,81 @@ +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() --