forked from auracaster/openocd
flash/nor/rp2040: flash bank target switching for RP2350
RP2350 can switch either core to Cortex-M33 or RISC-V. The different architectures have to be supported as distinct targets in OpenOCD. Introduce 'rp2xxx _switch target' Tcl command to adapt flash bank to architecture changes. Keep the target and priv pointers intact until a flash operation is finished to prevent sudden change in the middle of write/erase. Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Change-Id: I764354ab469e253042128958dfe70c09d04d6411 Reviewed-on: https://review.openocd.org/c/openocd/+/8448 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
@@ -627,16 +627,13 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2040_flash_bank
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_for_raw_flash_cmd(struct flash_bank *bank)
|
static int setup_for_raw_flash_cmd(struct target *target, struct rp2040_flash_bank *priv)
|
||||||
{
|
{
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
|
||||||
struct target *target = bank->target;
|
|
||||||
|
|
||||||
int err = ERROR_OK;
|
int err = ERROR_OK;
|
||||||
|
|
||||||
if (!priv->stack) {
|
if (!priv->stack) {
|
||||||
/* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
|
/* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
|
||||||
err = target_alloc_working_area(bank->target, RP2XXX_MAX_ALGO_STACK_USAGE, &priv->stack);
|
err = target_alloc_working_area(target, RP2XXX_MAX_ALGO_STACK_USAGE, &priv->stack);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("Could not allocate stack for flash programming code -- insufficient space");
|
LOG_ERROR("Could not allocate stack for flash programming code -- insufficient space");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
@@ -644,7 +641,7 @@ static int setup_for_raw_flash_cmd(struct flash_bank *bank)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!priv->ram_algo_space) {
|
if (!priv->ram_algo_space) {
|
||||||
err = target_alloc_working_area(bank->target, RP2XXX_MAX_RAM_ALGO_SIZE, &priv->ram_algo_space);
|
err = target_alloc_working_area(target, RP2XXX_MAX_RAM_ALGO_SIZE, &priv->ram_algo_space);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("Could not allocate RAM code space for ROM calls -- insufficient space");
|
LOG_ERROR("Could not allocate RAM code space for ROM calls -- insufficient space");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
@@ -692,7 +689,7 @@ static int setup_for_raw_flash_cmd(struct flash_bank *bank)
|
|||||||
.sp = priv->stack->address + priv->stack->size
|
.sp = priv->stack->address + priv->stack->size
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
err = rp2xxx_call_rom_func_batch(bank->target, priv, calls, 2);
|
err = rp2xxx_call_rom_func_batch(target, priv, calls, 2);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("RP2040 flash: failed to exit flash XIP mode");
|
LOG_ERROR("RP2040 flash: failed to exit flash XIP mode");
|
||||||
return err;
|
return err;
|
||||||
@@ -701,15 +698,13 @@ static int setup_for_raw_flash_cmd(struct flash_bank *bank)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanup_after_raw_flash_cmd(struct flash_bank *bank)
|
static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2040_flash_bank *priv)
|
||||||
{
|
{
|
||||||
/* OpenOCD is prone to trashing work-area allocations on target state
|
/* OpenOCD is prone to trashing work-area allocations on target state
|
||||||
transitions, which leaves us with stale work area pointers in our
|
transitions, which leaves us with stale work area pointers in our
|
||||||
driver state. Best to clean up our allocations manually after
|
driver state. Best to clean up our allocations manually after
|
||||||
completing each flash call, so we know to make fresh ones next time. */
|
completing each flash call, so we know to make fresh ones next time. */
|
||||||
LOG_DEBUG("Cleaning up after flash operations");
|
LOG_DEBUG("Cleaning up after flash operations");
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
|
||||||
struct target *target = bank->target;
|
|
||||||
if (priv->stack) {
|
if (priv->stack) {
|
||||||
target_free_working_area(target, priv->stack);
|
target_free_working_area(target, priv->stack);
|
||||||
priv->stack = 0;
|
priv->stack = 0;
|
||||||
@@ -728,7 +723,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui
|
|||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
struct working_area *bounce;
|
struct working_area *bounce;
|
||||||
|
|
||||||
int err = setup_for_raw_flash_cmd(bank);
|
int err = setup_for_raw_flash_cmd(target, priv);
|
||||||
if (err != ERROR_OK)
|
if (err != ERROR_OK)
|
||||||
goto cleanup_and_return;
|
goto cleanup_and_return;
|
||||||
|
|
||||||
@@ -780,7 +775,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui
|
|||||||
// accesses, but there's no harm in calling it anyway.
|
// accesses, but there's no harm in calling it anyway.
|
||||||
|
|
||||||
LOG_DEBUG("Flushing flash cache after write behind");
|
LOG_DEBUG("Flushing flash cache after write behind");
|
||||||
err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0);
|
err = rp2xxx_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0);
|
||||||
|
|
||||||
rp2xxx_rom_call_batch_record_t finishing_calls[3] = {
|
rp2xxx_rom_call_batch_record_t finishing_calls[3] = {
|
||||||
{
|
{
|
||||||
@@ -805,18 +800,19 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui
|
|||||||
goto cleanup_and_return;
|
goto cleanup_and_return;
|
||||||
}
|
}
|
||||||
cleanup_and_return:
|
cleanup_and_return:
|
||||||
cleanup_after_raw_flash_cmd(bank);
|
cleanup_after_raw_flash_cmd(target, priv);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
|
static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
|
||||||
{
|
{
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
uint32_t start_addr = bank->sectors[first].offset;
|
uint32_t start_addr = bank->sectors[first].offset;
|
||||||
uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
|
uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
|
||||||
LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
|
LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
|
||||||
|
|
||||||
int err = setup_for_raw_flash_cmd(bank);
|
int err = setup_for_raw_flash_cmd(target, priv);
|
||||||
if (err != ERROR_OK)
|
if (err != ERROR_OK)
|
||||||
goto cleanup_and_return;
|
goto cleanup_and_return;
|
||||||
|
|
||||||
@@ -855,7 +851,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig
|
|||||||
0xd8 /* block_cmd */
|
0xd8 /* block_cmd */
|
||||||
};
|
};
|
||||||
|
|
||||||
err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
|
err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
|
||||||
keep_alive();
|
keep_alive();
|
||||||
|
|
||||||
if (err != ERROR_OK)
|
if (err != ERROR_OK)
|
||||||
@@ -866,7 +862,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig
|
|||||||
|
|
||||||
|
|
||||||
cleanup_and_return:
|
cleanup_and_return:
|
||||||
cleanup_after_raw_flash_cmd(bank);
|
cleanup_after_raw_flash_cmd(target, priv);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,7 +969,8 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler)
|
|||||||
for (unsigned int i = 0; i + 1 < CMD_ARGC && i < ARRAY_SIZE(args); i++)
|
for (unsigned int i = 0; i + 1 < CMD_ARGC && i < ARRAY_SIZE(args); i++)
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i + 1], args[i]);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i + 1], args[i]);
|
||||||
|
|
||||||
retval = setup_for_raw_flash_cmd(bank);
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
retval = setup_for_raw_flash_cmd(target, priv);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto cleanup_and_return;
|
goto cleanup_and_return;
|
||||||
|
|
||||||
@@ -992,16 +989,51 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler)
|
|||||||
* in an event handler, use LOG_INFO instead */
|
* in an event handler, use LOG_INFO instead */
|
||||||
LOG_INFO("RP2xxx ROM API function %.2s @ %04" PRIx16, CMD_ARGV[0], fc);
|
LOG_INFO("RP2xxx ROM API function %.2s @ %04" PRIx16, CMD_ARGV[0], fc);
|
||||||
|
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
|
||||||
retval = rp2xxx_call_rom_func(target, priv, fc, args, ARRAY_SIZE(args));
|
retval = rp2xxx_call_rom_func(target, priv, fc, args, ARRAY_SIZE(args));
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
command_print(CMD, "RP2xxx ROM API call failed");
|
command_print(CMD, "RP2xxx ROM API call failed");
|
||||||
|
|
||||||
cleanup_and_return:
|
cleanup_and_return:
|
||||||
cleanup_after_raw_flash_cmd(bank);
|
cleanup_after_raw_flash_cmd(target, priv);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(rp2040_switch_target_handler)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC != 2)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
struct target *old_target = get_target(CMD_ARGV[0]);
|
||||||
|
if (!old_target) {
|
||||||
|
command_print(CMD, "Unrecognised old target %s", CMD_ARGV[0]);
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct target *new_target = get_target(CMD_ARGV[1]);
|
||||||
|
if (!new_target) {
|
||||||
|
command_print(CMD, "Unrecognised new target %s", CMD_ARGV[1]);
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_bank *bank;
|
||||||
|
for (bank = flash_bank_list(); bank; bank = bank->next) {
|
||||||
|
if (bank->driver == &rp2040_flash) {
|
||||||
|
if (bank->target == old_target) {
|
||||||
|
bank->target = new_target;
|
||||||
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
priv->probed = false;
|
||||||
|
return ERROR_OK;
|
||||||
|
} else if (bank->target == new_target) {
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(CMD, "Neither old nor new target %s found in flash bank list",
|
||||||
|
CMD_ARGV[0]);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct command_registration rp2040_exec_command_handlers[] = {
|
static const struct command_registration rp2040_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "rom_api_call",
|
.name = "rom_api_call",
|
||||||
@@ -1010,6 +1042,13 @@ static const struct command_registration rp2040_exec_command_handlers[] = {
|
|||||||
.usage = "fc [p0 [p1 [p2 [p3]]]]",
|
.usage = "fc [p0 [p1 [p2 [p3]]]]",
|
||||||
.handler = rp2040_rom_api_call_handler,
|
.handler = rp2040_rom_api_call_handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "_switch_target",
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "internal use",
|
||||||
|
.usage = "old_target new_target",
|
||||||
|
.handler = rp2040_switch_target_handler,
|
||||||
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user