2
0
mirror of git://git.code.sf.net/p/openocd/code synced 2025-08-15 11:36:46 +10:00

flash/bluenrg-x: support programming without loader

fallback programming without loader when resources are not available
while at there refactor reused code
(wait for interrupt and command execution)

Change-Id: I2cba0f53d3470bc324f4a72614c236cebf196f64
Signed-off-by: BOCHKATI Tarek <tarek.bochkati@st.com>
Signed-off-by: HAOUES Ahmed <ahmed.haoues@st.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/8883
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
HAOUES Ahmed 2025-05-27 11:42:42 +01:00 committed by Antonio Borneo
parent 37a0f013f8
commit 2da332fa83
2 changed files with 126 additions and 46 deletions

View File

@ -143,8 +143,45 @@ static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg
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;
@ -186,19 +223,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first,
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");
if (bluenrgx_wait_for_command(bank) != ERROR_OK)
return ERROR_FAIL;
}
if (value & FLASH_INT_CMDDONE)
break;
if (i == 99) {
LOG_ERROR("Mass erase command failed (timeout)");
retval = ERROR_FAIL;
}
}
} else {
command = FLASH_CMD_ERASE_PAGE;
@ -222,27 +248,16 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first,
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");
if (bluenrgx_wait_for_command(bank) != ERROR_OK)
return ERROR_FAIL;
}
if (value & FLASH_INT_CMDDONE)
break;
if (j == 99) {
LOG_ERROR("Erase command failed (timeout)");
retval = ERROR_FAIL;
}
}
}
}
return retval;
}
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;
@ -264,22 +279,6 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
#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");
@ -366,6 +365,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
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 */
@ -377,6 +377,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
}
}
}
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
target_free_working_area(target, write_algorithm_stack);
@ -391,6 +392,80 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
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;

View File

@ -28,7 +28,12 @@
#define FLASH_CMD_WRITE 0x33
#define FLASH_CMD_BURSTWRITE 0xCC
#define FLASH_INT_CMDDONE 0x01
#define FLASH_INT_CMDSTART 0x02
/* Flash Controller constants */
#define FLASH_WORD_LEN 4
#define FLASH_DATA_WIDTH_W 4
#define FLASH_DATA_WIDTH 16
#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */