#include <target/algorithm.h>
#include <target/armv7m.h>
#include <helper/types.h>
+#include <helper/time_support.h>
enum {
NRF5_FLASH_BASE = 0x00000000,
enum nrf5_nvmc_registers {
NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory
- * Controller Regsters */
+ * Controller Registers */
#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset)
struct nrf5_info {
uint32_t code_page_size;
+ uint32_t refcount;
- struct {
+ struct nrf5_bank {
+ struct nrf5_info *chip;
bool probed;
- int (*write) (struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count);
} bank[2];
struct target *target;
};
.flash_size_kb = (fsize), \
}
-/* The known devices table below is derived from the "nRF51 Series
- * Compatibility Matrix" document, which can be found by searching for
- * ATTN-51 on the Nordic Semi website:
+/* The known devices table below is derived from the "nRF5x series
+ * compatibility matrix" documents, which can be found in the "DocLib" of
+ * nordic:
*
- * http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview
+ * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview
*
* Up to date with Matrix v2.0, plus some additional HWIDs.
*
NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
+ /* nRF52810 Devices */
+ NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192),
+ NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192),
+
/* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
+ NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512),
+
+ /* nRF52840 Devices */
+ NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
};
static int nrf5_bank_is_probed(struct flash_bank *bank)
{
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
- assert(chip != NULL);
+ assert(nbank != NULL);
- return chip->bank[bank->bank_number].probed;
+ return nbank->probed;
}
static int nrf5_probe(struct flash_bank *bank);
return ERROR_TARGET_NOT_HALTED;
}
- *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ *chip = nbank->chip;
int probed = nrf5_bank_is_probed(bank);
if (probed < 0)
{
uint32_t ready;
int res;
- int timeout = 100;
+ int timeout_ms = 340;
+ int64_t ts_start = timeval_ms();
do {
res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready);
if (ready == 0x00000001)
return ERROR_OK;
- alive_sleep(1);
- } while (timeout--);
+ keep_alive();
+
+ } while ((timeval_ms()-ts_start) < timeout_ms);
LOG_DEBUG("Timed out waiting for NVMC_READY");
return ERROR_FLASH_BUSY;
if (bank->base == NRF5_UICR_BASE)
return ERROR_OK;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
assert(chip != NULL);
{
uint32_t hwid;
int res;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid);
if (res != ERROR_OK) {
/* Start a low level flash write for the specified region */
-static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
+static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes)
{
struct target *target = chip->target;
uint32_t buffer_size = 8192;
struct working_area *write_algorithm;
struct working_area *source;
- uint32_t address = NRF5_FLASH_BASE + offset;
struct reg_param reg_params[4];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
-
- LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
+ LOG_DEBUG("Writing buffer to flash address=0x%"PRIx32" bytes=0x%"PRIx32, address, bytes);
assert(bytes % 4 == 0);
/* allocate working area with flash programming code */
LOG_WARNING("no working area available, falling back to slow memory writes");
for (; bytes > 0; bytes -= 4) {
- retval = target_write_memory(chip->target, offset, 4, 1, buffer);
+ retval = target_write_memory(target, address, 4, 1, buffer);
if (retval != ERROR_OK)
return retval;
if (retval != ERROR_OK)
return retval;
- offset += 4;
+ address += 4;
buffer += 4;
}
return ERROR_OK;
}
- LOG_WARNING("using fast async flash loader. This is currently supported");
- LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
- LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it");
-
retval = target_write_buffer(target, write_algorithm->address,
sizeof(nrf5_flash_write_code),
nrf5_flash_write_code);
return retval;
}
-/* Check and erase flash sectors in specified range then start a low level page write.
- start/end must be sector aligned.
-*/
-static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
+static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
{
- int res = ERROR_FAIL;
- struct nrf5_info *chip = bank->driver_priv;
+ struct nrf5_info *chip;
+
+ int res = nrf5_get_probed_chip_if_halted(bank, &chip);
+ if (res != ERROR_OK)
+ return res;
- assert(start % chip->code_page_size == 0);
- assert(end % chip->code_page_size == 0);
+ assert(offset % 4 == 0);
+ assert(count % 4 == 0);
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
- res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
+ res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count);
if (res != ERROR_OK)
goto error;
return res;
}
-static int nrf5_code_flash_write(struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count)
-{
-
- int res;
- /* Need to perform reads to fill any gaps we need to preserve in the first page,
- before the start of buffer, or in the last page, after the end of buffer */
- uint32_t first_page = offset/chip->code_page_size;
- uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
-
- uint32_t first_page_offset = first_page * chip->code_page_size;
- uint32_t last_page_offset = last_page * chip->code_page_size;
-
- LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
- offset, offset+count, first_page_offset, last_page_offset);
-
- uint32_t page_cnt = last_page - first_page;
- uint8_t buffer_to_flash[page_cnt*chip->code_page_size];
-
- /* Fill in any space between start of first page and start of buffer */
- uint32_t pre = offset - first_page_offset;
- if (pre > 0) {
- res = target_read_memory(bank->target,
- first_page_offset,
- 1,
- pre,
- buffer_to_flash);
- if (res != ERROR_OK)
- return res;
- }
-
- /* Fill in main contents of buffer */
- memcpy(buffer_to_flash+pre, buffer, count);
-
- /* Fill in any space between end of buffer and end of last page */
- uint32_t post = last_page_offset - (offset+count);
- if (post > 0) {
- /* Retrieve the full row contents from Flash */
- res = target_read_memory(bank->target,
- offset + count,
- 1,
- post,
- buffer_to_flash+pre+count);
- if (res != ERROR_OK)
- return res;
- }
-
- return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
-}
-
-static int nrf5_uicr_flash_write(struct flash_bank *bank,
- struct nrf5_info *chip,
- const uint8_t *buffer, uint32_t offset, uint32_t count)
+static void nrf5_free_driver_priv(struct flash_bank *bank)
{
- int res;
- uint8_t uicr[NRF5_UICR_SIZE];
- struct flash_sector *sector = &bank->sectors[0];
-
- if ((offset + count) > NRF5_UICR_SIZE)
- return ERROR_FAIL;
-
- res = target_read_memory(bank->target,
- NRF5_UICR_BASE,
- 1,
- NRF5_UICR_SIZE,
- uicr);
-
- if (res != ERROR_OK)
- return res;
-
- res = nrf5_erase_page(bank, chip, sector);
- if (res != ERROR_OK)
- return res;
-
- res = nrf5_nvmc_write_enable(chip);
- if (res != ERROR_OK)
- return res;
-
- memcpy(&uicr[offset], buffer, count);
-
- res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE);
- if (res != ERROR_OK) {
- nrf5_nvmc_read_only(chip);
- return res;
+ struct nrf5_bank *nbank = bank->driver_priv;
+ struct nrf5_info *chip = nbank->chip;
+ if (chip == NULL)
+ return;
+
+ chip->refcount--;
+ if (chip->refcount == 0) {
+ free(chip);
+ bank->driver_priv = NULL;
}
-
- return nrf5_nvmc_read_only(chip);
}
-
-static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
-{
- int res;
- struct nrf5_info *chip;
-
- res = nrf5_get_probed_chip_if_halted(bank, &chip);
- if (res != ERROR_OK)
- return res;
-
- return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
-}
-
-
FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
{
static struct nrf5_info *chip;
+ struct nrf5_bank *nbank = NULL;
switch (bank->base) {
case NRF5_FLASH_BASE:
- bank->bank_number = 0;
- break;
case NRF5_UICR_BASE:
- bank->bank_number = 1;
break;
default:
- LOG_ERROR("Invalid bank address 0x%08" PRIx32, bank->base);
+ LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
return ERROR_FAIL;
}
switch (bank->base) {
case NRF5_FLASH_BASE:
- chip->bank[bank->bank_number].write = nrf5_code_flash_write;
+ nbank = &chip->bank[0];
break;
case NRF5_UICR_BASE:
- chip->bank[bank->bank_number].write = nrf5_uicr_flash_write;
+ nbank = &chip->bank[1];
break;
}
+ assert(nbank != NULL);
- chip->bank[bank->bank_number].probed = false;
- bank->driver_priv = chip;
+ chip->refcount++;
+ nbank->chip = chip;
+ nbank->probed = false;
+ bank->driver_priv = nbank;
+ bank->write_start_alignment = bank->write_end_alignment = 4;
return ERROR_OK;
}
.handler = nrf5_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase all flash contents of the chip.",
+ .usage = "",
},
COMMAND_REGISTRATION_DONE
};
COMMAND_REGISTRATION_DONE
};
-struct flash_driver nrf5_flash = {
+const struct flash_driver nrf5_flash = {
.name = "nrf5",
.commands = nrf5_command_handlers,
.flash_bank_command = nrf5_flash_bank_command,
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
+ .free_driver_priv = nrf5_free_driver_priv,
};
/* We need to retain the flash-driver name as well as the commands
* for backwards compatability */
-struct flash_driver nrf51_flash = {
+const struct flash_driver nrf51_flash = {
.name = "nrf51",
.commands = nrf5_command_handlers,
.flash_bank_command = nrf5_flash_bank_command,
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
+ .free_driver_priv = nrf5_free_driver_priv,
};