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:
parent
37a0f013f8
commit
2da332fa83
@ -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);
|
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,
|
static int bluenrgx_wait_for_interrupt(struct flash_bank *bank, uint32_t interrupt_flag)
|
||||||
unsigned int last)
|
{
|
||||||
|
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;
|
int retval = ERROR_OK;
|
||||||
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
|
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;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 100; i++) {
|
if (bluenrgx_wait_for_command(bank) != ERROR_OK)
|
||||||
uint32_t value;
|
return ERROR_FAIL;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
command = FLASH_CMD_ERASE_PAGE;
|
command = FLASH_CMD_ERASE_PAGE;
|
||||||
@ -222,19 +248,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first,
|
|||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int j = 0; j < 100; j++) {
|
if (bluenrgx_wait_for_command(bank) != ERROR_OK)
|
||||||
uint32_t value;
|
return ERROR_FAIL;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +257,7 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
uint32_t offset, uint32_t count)
|
||||||
{
|
{
|
||||||
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
|
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"
|
#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),
|
if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code),
|
||||||
&write_algorithm) != ERROR_OK) {
|
&write_algorithm) != ERROR_OK) {
|
||||||
LOG_WARNING("no working area available, can't do block memory writes");
|
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)
|
if (error != 0)
|
||||||
LOG_ERROR("flash write failed = %08" PRIx32, error);
|
LOG_ERROR("flash write failed = %08" PRIx32, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval == ERROR_OK) {
|
if (retval == ERROR_OK) {
|
||||||
uint32_t rp;
|
uint32_t rp;
|
||||||
/* Read back rp and check that is valid */
|
/* 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, source);
|
||||||
target_free_working_area(target, write_algorithm);
|
target_free_working_area(target, write_algorithm);
|
||||||
target_free_working_area(target, write_algorithm_stack);
|
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;
|
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)
|
static int bluenrgx_probe(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
|
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
|
||||||
@ -428,7 +503,7 @@ static int bluenrgx_probe(struct flash_bank *bank)
|
|||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
bank->size = (size_info + 1) * FLASH_WORD_LEN;
|
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);
|
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < bank->num_sectors; i++) {
|
for (unsigned int i = 0; i < bank->num_sectors; i++) {
|
||||||
|
@ -28,7 +28,12 @@
|
|||||||
#define FLASH_CMD_WRITE 0x33
|
#define FLASH_CMD_WRITE 0x33
|
||||||
#define FLASH_CMD_BURSTWRITE 0xCC
|
#define FLASH_CMD_BURSTWRITE 0xCC
|
||||||
#define FLASH_INT_CMDDONE 0x01
|
#define FLASH_INT_CMDDONE 0x01
|
||||||
|
#define FLASH_INT_CMDSTART 0x02
|
||||||
|
|
||||||
|
/* Flash Controller constants */
|
||||||
#define FLASH_WORD_LEN 4
|
#define FLASH_WORD_LEN 4
|
||||||
|
#define FLASH_DATA_WIDTH_W 4
|
||||||
|
#define FLASH_DATA_WIDTH 16
|
||||||
|
|
||||||
|
|
||||||
#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */
|
#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user