return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
}
-static int bluenrgx_erase(struct flash_bank *bank, unsigned int first,
- unsigned int last)
+static int bluenrgx_wait_for_interrupt(struct flash_bank *bank, uint32_t interrupt_flag)
+{
+ bool flag_raised = false;
+ for (unsigned int j = 0; j < 100; j++) {
+ uint32_t value;
+ if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value) != ERROR_OK) {
+ LOG_ERROR("Register read failed");
+ return ERROR_FAIL;
+ }
+
+ if (value & interrupt_flag) {
+ flag_raised = true;
+ break;
+ }
+ }
+
+ /* clear the interrupt */
+ if (flag_raised) {
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, interrupt_flag) != ERROR_OK) {
+ LOG_ERROR("Cannot clear interrupt flag");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+ }
+
+ LOG_ERROR("Erase command failed (timeout)");
+ return ERROR_TIMEOUT_REACHED;
+}
+
+static inline int bluenrgx_wait_for_command(struct flash_bank *bank)
+{
+ if (bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDSTART) == ERROR_OK)
+ return bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDDONE);
+
+ return ERROR_FAIL;
+}
+
+static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
{
int retval = ERROR_OK;
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
return ERROR_FAIL;
}
- for (unsigned int i = 0; i < 100; i++) {
- uint32_t value;
- if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
- LOG_ERROR("Register write failed");
- return ERROR_FAIL;
- }
- if (value & FLASH_INT_CMDDONE)
- break;
- if (i == 99) {
- LOG_ERROR("Mass erase command failed (timeout)");
- retval = ERROR_FAIL;
- }
- }
+ if (bluenrgx_wait_for_command(bank) != ERROR_OK)
+ return ERROR_FAIL;
} else {
command = FLASH_CMD_ERASE_PAGE;
return ERROR_FAIL;
}
- for (unsigned int j = 0; j < 100; j++) {
- uint32_t value;
- if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
- LOG_ERROR("Register write failed");
- return ERROR_FAIL;
- }
- if (value & FLASH_INT_CMDDONE)
- break;
- if (j == 99) {
- LOG_ERROR("Erase command failed (timeout)");
- retval = ERROR_FAIL;
- }
- }
+ if (bluenrgx_wait_for_command(bank) != ERROR_OK)
+ return ERROR_FAIL;
}
}
}
-static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
+static int bluenrgx_write_with_loader(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
};
- /* check preconditions */
- if (!bluenrgx_info->probed)
- return ERROR_FLASH_BANK_NOT_PROBED;
-
- if ((offset + count) > bank->size) {
- LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32,
- (offset + count),
- bank->size);
- return ERROR_FLASH_DST_OUT_OF_BANK;
- }
-
- if (bank->target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
if (error != 0)
LOG_ERROR("flash write failed = %08" PRIx32, error);
}
+
if (retval == ERROR_OK) {
uint32_t rp;
/* Read back rp and check that is valid */
}
}
}
+
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
target_free_working_area(target, write_algorithm_stack);
return retval;
}
+static int bluenrgx_write_without_loader(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ unsigned int data_count = count / FLASH_DATA_WIDTH;
+
+ while (data_count--) {
+ /* clear flags */
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
+ LOG_ERROR("Register write failed");
+ return ERROR_FAIL;
+ }
+
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, offset >> 2) != ERROR_OK) {
+ LOG_ERROR("Register write failed");
+ return ERROR_FAIL;
+ }
+
+ if (target_write_memory(target, bluenrgx_get_flash_reg(bank, FLASH_REG_DATA0),
+ FLASH_WORD_LEN, FLASH_DATA_WIDTH_W, buffer) != ERROR_OK) {
+ LOG_ERROR("Failed to write data");
+ return ERROR_FAIL;
+ }
+
+ if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, FLASH_CMD_BURSTWRITE) != ERROR_OK) {
+ LOG_ERROR("Failed");
+ return ERROR_FAIL;
+ }
+
+ if (bluenrgx_wait_for_command(bank) != ERROR_OK)
+ return ERROR_FAIL;
+
+ /* increment offset, and buffer */
+ offset += FLASH_DATA_WIDTH;
+ buffer += FLASH_DATA_WIDTH;
+ }
+
+ return ERROR_OK;
+}
+
+static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
+ int retval = ERROR_OK;
+
+ /* check preconditions */
+ if (!bluenrgx_info->probed)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if ((offset + count) > bank->size) {
+ LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32,
+ (offset + count),
+ bank->size);
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+ }
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ assert(offset % FLASH_WORD_LEN == 0);
+ assert(count % FLASH_WORD_LEN == 0);
+
+ retval = bluenrgx_write_with_loader(bank, buffer, offset, count);
+ /* if resources are not available write without a loader */
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+ LOG_WARNING("falling back to programming without a flash loader (slower)");
+ retval = bluenrgx_write_without_loader(bank, buffer, offset, count);
+ }
+ return retval;
+}
+
static int bluenrgx_probe(struct flash_bank *bank)
{
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
return retval;
bank->size = (size_info + 1) * FLASH_WORD_LEN;
- bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info);
+ bank->num_sectors = bank->size / FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
for (unsigned int i = 0; i < bank->num_sectors; i++) {