This is an automated email from Gerrit.

"zapb <d...@zapb.de>" just uploaded a new patch set to Gerrit, which you can 
find at https://review.openocd.org/c/openocd/+/8818

-- gerrit

commit 53e1af97dc1489c83dba658281158366514a96a2
Author: Marc Schink <d...@zapb.de>
Date:   Sun Mar 16 11:17:25 2025 +0000

    flash/nor: Add nRF54 NVM driver
    
    The driver is intentionally not integrated into the 'nRF5' driver in order 
to
    serve as a kind of 'test vehicle' for non-flash memory drivers.
    
    The driver does not support the UICR but only the main memory region.
    
    Change-Id: Ia69527c4e07d40e8805186be8e988c0d74c12041
    Signed-off-by: Marc Schink <d...@zapb.de>

diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 147807fbaa..f94eff606e 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -51,6 +51,7 @@ NOR_DRIVERS = \
        %D%/non_cfi.c \
        %D%/npcx.c \
        %D%/nrf5.c \
+       %D%/nrf54.c \
        %D%/numicro.c \
        %D%/ocl.c \
        %D%/pic32mx.c \
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 794566f121..84022e548c 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -279,6 +279,7 @@ 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 nrf5_flash;
+extern const struct flash_driver nrf54_flash;
 extern const struct flash_driver numicro_flash;
 extern const struct flash_driver ocl_flash;
 extern const struct flash_driver pic32mx_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 67d86243b7..dab6aadef9 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -56,6 +56,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &npcx_flash,
        &nrf5_flash,
        &nrf51_flash,
+       &nrf54_flash,
        &numicro_flash,
        &ocl_flash,
        &pic32mx_flash,
diff --git a/src/flash/nor/nrf54.c b/src/flash/nor/nrf54.c
new file mode 100644
index 0000000000..ccd9b6b6fb
--- /dev/null
+++ b/src/flash/nor/nrf54.c
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <helper/types.h>
+#include <helper/time_support.h>
+#include <helper/bits.h>
+
+/*
+ * Related documents
+ *
+ * nRF54L15, nRF54L10, and nRF54L05 Wireless SoCs
+ * 
https://docs-be.nordicsemi.com/bundle/ps_nrf54L15/page/pdf/nRF54L15_nRF54L10_nRF54L05_Datasheet_v0.8.pdf
+ *
+ * nRF54L Series Production Programming
+ * https://docs-be.nordicsemi.com/bundle/nan_047/attach/nan_047.pdf
+ */
+
+#define NRF54_FICR_BASE_ADDR                   0x00FFC000
+
+#define NRF54_FICR_INFO_PART_REG               0x31c
+#define NRF54_FICR_INFO_VARIANT_REG            0x320
+#define NRF54_FICR_INFO_PACKAGE_REG            0x324
+#define NRF54_FICR_INFO_RAM_REG                        0x328
+#define NRF54_FICR_INFO_RRAM_REG               0x32C
+
+#define NRF54_RRAM_BASE_ADDR   0x00000000
+
+#define NRF54_RRAMC_BASE_ADDR  0x5004B000
+
+#define NRF54_RRAMC_REG_CONFIG 0x500
+#define NRF54_RRAMC_REG_READY  0x400
+
+#define NRF54_RRAMC_CONFIG_WEN BIT(0)
+
+struct {
+       uint32_t id;
+       const char *name;
+} nrf54_part_names[] = {
+       { 0x00054B15, "nRF54L15" },
+       { 0x00054B10, "nRF54L10" },
+       { 0x00054B05, "nRF54L05" },
+};
+
+struct nrf54_ficr_info {
+               // Part identification number.
+               uint32_t part;
+               /*
+                * Part variant (V), hardware version (H) and production
+                * configuration (P) encoded as ASCII: <VV><H><P>.
+                */
+               uint32_t variant;
+               /*
+                * Package variant (P) encoded as ASCII: <__><PP>, where (_) 
indicates
+                * the null character.
+                */
+               uint32_t package;
+               // SRAM size in KiB.
+               uint32_t sram_size;
+               // RRAM size in KiB.
+               uint32_t rram_size;
+};
+
+struct nrf54_info {
+       bool probed;
+       const char *part_name;
+
+       struct nrf54_ficr_info ficr_info;
+};
+
+static int nrf54_read_ficr_info(struct target *target,
+               struct nrf54_ficr_info *info)
+{
+       int retval = target_read_u32(target,
+               NRF54_FICR_BASE_ADDR + NRF54_FICR_INFO_PART_REG, &info->part);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target,
+               NRF54_FICR_BASE_ADDR + NRF54_FICR_INFO_VARIANT_REG, 
&info->variant);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target,
+               NRF54_FICR_BASE_ADDR + NRF54_FICR_INFO_PACKAGE_REG, 
&info->package);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target,
+               NRF54_FICR_BASE_ADDR + NRF54_FICR_INFO_RAM_REG, 
&info->sram_size);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target,
+               NRF54_FICR_BASE_ADDR + NRF54_FICR_INFO_RRAM_REG, 
&info->rram_size);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static const char *nrf54_get_part_name(uint32_t id)
+{
+       for (size_t i = 0; i < ARRAY_SIZE(nrf54_part_names); i++) {
+               if (id == nrf54_part_names[i].id)
+                       return nrf54_part_names[i].name;
+       }
+
+       return NULL;
+}
+
+static void nrf54_u32_to_str(uint32_t data, char *str)
+{
+       uint8_t tmp[4];
+
+       h_u32_to_be(tmp, data);
+       memcpy(str, tmp, 4);
+       str[4] = '\0';
+}
+
+static bool nrf54_get_chip_type_str(const struct nrf54_info *info,
+               char *buf, size_t size)
+{
+       char variant[5];
+       nrf54_u32_to_str(info->ficr_info.variant, variant);
+
+       char package[5];
+       // Note that the first two characters are always null characters.
+       nrf54_u32_to_str(info->ficr_info.package, package);
+
+       int res = snprintf(buf, size, "%s-%c%c%c%c",
+               info->part_name, package[2], package[3], variant[0], 
variant[1]);
+
+       if (res < 0)
+               return false;
+
+       if ((size_t)res >= size)
+               return false;
+
+       return true;
+}
+
+static int nrf54_protect_check(struct flash_bank *bank)
+{
+       return ERROR_FLASH_OPER_UNSUPPORTED;
+}
+
+static int nrf54_protect(struct flash_bank *bank, int set, unsigned int first,
+               unsigned int last)
+{
+       return ERROR_FLASH_OPER_UNSUPPORTED;
+}
+
+static int nrf54_info(struct flash_bank *bank, struct command_invocation *cmd)
+{
+       struct nrf54_info *info = bank->driver_priv;
+
+       char chip_type[128];
+       if (!nrf54_get_chip_type_str(info, chip_type, sizeof(chip_type))) {
+               LOG_ERROR("Failed to build chip type string");
+               return ERROR_FAIL;
+       }
+
+       command_print_sameline(cmd, "%s %" PRIu32 " KiB RRAM, %" PRIu32 " KiB 
SRAM",
+               chip_type, info->ficr_info.rram_size, 
info->ficr_info.sram_size);
+
+       return ERROR_OK;
+}
+
+
+static int nrf54_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct nrf54_info *nrf54_info = bank->driver_priv;
+       struct nrf54_ficr_info *ficr_info = &nrf54_info->ficr_info;
+
+       int retval = nrf54_read_ficr_info(target, ficr_info);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Failed to load FICR from device");
+               return retval;
+       }
+
+       const char *part_name = nrf54_get_part_name(ficr_info->part);
+
+       if (!part_name) {
+               LOG_ERROR("Unknown device with part number 0x%08" PRIx32,
+                       nrf54_info->ficr_info.part);
+               return ERROR_FAIL;
+       }
+
+       nrf54_info->part_name = part_name;
+       bank->size = ficr_info->sram_size * 1024;
+
+       nrf54_info->probed = true;
+
+       // RRAM has no alignment constraints, see section 4.2.6.2 in the 
datasheet.
+       bank->write_start_alignment = 0;
+       bank->write_end_alignment = 0;
+
+       return ERROR_OK;
+}
+
+static int nrf54_auto_probe(struct flash_bank *bank)
+{
+       struct nrf54_info *info = bank->driver_priv;
+
+       if (!info->probed)
+               return nrf54_probe(bank);
+
+       return ERROR_OK;
+}
+
+static int nrf54_wait_until_ready(struct target *target, uint32_t timeout)
+{
+       const int64_t start_time = timeval_ms();
+
+       while (true) {
+               uint32_t ready;
+               int retval = target_read_u32(target,
+                       NRF54_RRAMC_BASE_ADDR + NRF54_RRAMC_REG_READY, &ready);
+
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (ready)
+                       break;
+
+               if ((timeval_ms() - start_time) > timeout) {
+                       LOG_ERROR("Timed out waiting for RRAM");
+                       return ERROR_FAIL;
+               }
+
+               keep_alive();
+       }
+
+       return ERROR_OK;
+}
+
+static int nrf54_write(struct flash_bank *bank, const uint8_t *buffer,
+                                       uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       // Write buffer size in 128-bit words, we always use the maximum.
+       const uint32_t write_buffer_size = 32;
+
+       // Unlock RRAM to enables writes and configure the write buffer size.
+       int retval = target_write_u32(target,
+               NRF54_RRAMC_BASE_ADDR + NRF54_RRAMC_REG_CONFIG,
+               (write_buffer_size << 8) | NRF54_RRAMC_CONFIG_WEN);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Failed to unlock RRAM");
+               return retval;
+       }
+
+       retval = nrf54_wait_until_ready(target, 1000);
+       if (retval != ERROR_OK)
+               goto error;
+
+       // See section (4.2.6.2) in the datasheet about writing to RRAM.
+       const uint32_t buffer_size = (write_buffer_size == 0) ?
+               4 : write_buffer_size * 16;
+
+       while (count > 0) {
+               const uint32_t write_size = MIN(buffer_size, count);
+               retval = target_write_buffer(target, bank->base + offset, 
write_size,
+                       buffer);
+
+               if (retval != ERROR_OK)
+                       goto error;
+
+               retval = nrf54_wait_until_ready(target, 1000);
+               if (retval != ERROR_OK)
+                       goto error;
+
+               offset += write_size;
+               buffer += write_size;
+               count -= write_size;
+       }
+
+       // Check if there is data in the write-buffer that needs to be 
committed.
+       uint32_t buf_status;
+       retval = target_read_u32(target, NRF54_RRAMC_BASE_ADDR + 0x418, 
&buf_status);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Failed to read write-buffer status");
+               goto error;
+       }
+
+       if (!buf_status) {
+               LOG_DEBUG("Commit data from write-buffer to RRAM");
+
+               retval = target_write_u32(target, NRF54_RRAMC_BASE_ADDR + 0x8, 
0x1);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Failed to start write-buffer commit task");
+                       goto error;
+               }
+
+               retval = nrf54_wait_until_ready(target, 1000);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Timed out during write-buffer commit task");
+                       goto error;
+               }
+       }
+
+error:
+       // Lock RRAMC and disable writes.
+       int retval_lock = target_write_u32(target,
+               NRF54_RRAMC_BASE_ADDR + NRF54_RRAMC_REG_CONFIG, 0x0);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (retval_lock != ERROR_OK) {
+               LOG_ERROR("Failed to lock RRAMC");
+               return retval_lock;
+       }
+
+       return ERROR_OK;
+}
+
+static int nrf54_erase(struct flash_bank *bank, unsigned int first,
+               unsigned int last)
+{
+       return ERROR_FLASH_OPER_UNSUPPORTED;
+}
+
+static void nrf54_free_driver_priv(struct flash_bank *bank)
+{
+       free(bank->driver_priv);
+}
+
+FLASH_BANK_COMMAND_HANDLER(nrf54_flash_bank_command)
+{
+       if (bank->base != NRF54_RRAM_BASE_ADDR) {
+               LOG_ERROR("Bank base address must be %" PRIx32, 
NRF54_RRAM_BASE_ADDR);
+               return ERROR_FAIL;
+       }
+
+       struct nrf54_info *nrf54_info = calloc(1, sizeof(struct nrf54_info));
+
+       if (!nrf54_info) {
+               LOG_ERROR("Failed to allocate memory");
+               return ERROR_FAIL;
+       }
+
+
+       nrf54_info->probed = false;
+       bank->driver_priv = nrf54_info;
+
+       return ERROR_OK;
+}
+
+static const struct command_registration nrf54_command_handlers[] = {
+       {
+               .name   = "nrf54",
+               .mode   = COMMAND_ANY,
+               .help   = "nrf54 flash command group",
+               .usage  = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct flash_driver nrf54_flash = {
+       .name = "nrf54",
+       .commands = nrf54_command_handlers,
+       .flash_bank_command = nrf54_flash_bank_command,
+       .info = nrf54_info,
+       .erase = nrf54_erase,
+       .protect = nrf54_protect,
+       .write = nrf54_write,
+       .read = default_flash_read,
+       .probe = nrf54_probe,
+       .auto_probe     = nrf54_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = nrf54_protect_check,
+       .free_driver_priv = nrf54_free_driver_priv,
+};

-- 

Reply via email to