This is an automated email from Gerrit. "Tomas Vanek <van...@fbl.cz>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8440
-- gerrit commit 9e9e8f136d0d04fbfd38a4daef8fb08a63a71a4a Author: graham sanderson <graham.sander...@raspberrypi.com> Date: Fri Nov 3 15:55:41 2023 -0500 flash/nor/rp2040: add RP2350 support TV: Extracted RP2040/2350 flash driver part only. Fixed style problems. Change-Id: I88a7d5aa0a239ae93d72bd5671686b19c6ca11ad Signed-off-by: Tomas Vanek <van...@fbl.cz> diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index b2ebd9c49e..c53b54754a 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -9,14 +9,19 @@ #include <target/algorithm.h> #include <target/armv7m.h> #include "spi.h" +#include <target/cortex_m.h> /* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010 Your gdbinit should load the bootrom.elf if appropriate */ /* this is 'M' 'u', 1 (version) */ -#define BOOTROM_MAGIC 0x01754d +#define BOOTROM_RP2040_MAGIC 0x01754d +/* this is 'M' 'u', 2 (version) */ +#define BOOTROM_RP2350_MAGIC 0x02754d #define BOOTROM_MAGIC_ADDR 0x00000010 +#define RT_ARM_FUNC 0x1 + /* Call a ROM function via the debug trampoline Up to four arguments passed in r0...r3 as per ABI Function address is passed in r7 @@ -31,6 +36,48 @@ #define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') #define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') #define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') +#define FUNC_BOOTROM_STATE_RESET MAKE_TAG('S', 'R') + +// these form a bit set +#define BOOTROM_STATE_RESET_CURRENT_CORE 0x01 +#define BOOTROM_STATE_RESET_OTHER_CORE 0x02 +#define BOOTROM_STATE_RESET_GLOBAL_STATE 0x04 + +#define ACCESSCTRL_LOCK_OFFSET 0x40060000u +#define ACCESSCTRL_LOCK_DEBUG_BITS 0x00000008u +#define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u +#define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u + +// Calling bootrom functions requires the redundancy coprocessor (RCP) to be +// initialised. Usually this is done first thing by the bootrom, but the +// debugger may skip this, e.g. by resetting the cores and then running a +// NO_FLASH binary, or by reset-halting the cores before flash programming. +// +// The first case can be handled by a stub in the binary itself to initialise +// the RCP with dummy values if the bootrom has not already initialised it. +// (Note this case is only reachable via the debugger.) The second case +// requires the debugger itself to initialise the RCP, using this stub code: + +static const int rcp_init_code_bkpt_offset = 24; +static const uint16_t rcp_init_code[] = { + // Just enable the RCP which is fine if it already was (we assume no other + // co-processors are enabled at this point to save space) + 0x4806, // ldr r0, = PPB_BASE + M33_CPACR_OFFSET + 0xf45f, 0x4140, // movs r1, #M33_CPACR_CP7_BITS + 0x6001, // str r1, [r0] + // Only initialize canary seeds if they haven't been (as to do so twice is a fault) + 0xee30, 0xf710, // mrc p7, #1, r15, c0, c0, #0 + 0xd404, // bmi 1f + // Todo should we use something random here and pass it into the algorithm? + 0xec40, 0x0780, // mcrr p7, #8, r0, r0, c0 + 0xec40, 0x0781, // mcrr p7, #8, r0, r0, c1 + // Let other core know + 0xbf40, // sev + // 1: + 0xbe00, // bkpt (end of algorithm) + 0x0000, // pad + 0xed88, 0xe000 // PPB_BASE + M33_CPACR_OFFSET +}; struct rp2040_flash_bank { /* flag indicating successful flash probe */ @@ -46,33 +93,31 @@ struct rp2040_flash_bank { uint16_t jump_flash_range_program; uint16_t jump_flush_cache; uint16_t jump_enter_cmd_xip; - /* detected model of SPI flash */ - const struct flash_device *dev; + uint16_t jump_bootrom_reset_state; }; -/* guessed SPI flash description if autodetection disabled (same as win w25q16jv) */ -static const struct flash_device rp2040_default_spi_device = - FLASH_ID("autodetect disabled", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0, 0x100, 0x10000, 0); - static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol) { - uint32_t magic; + uint32_t magic, magic_addr; + bool found_rp2040_magic, found_rp2350_magic; + magic_addr = BOOTROM_MAGIC_ADDR; int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); if (err != ERROR_OK) return err; magic &= 0xffffff; /* ignore bootrom version */ - if (magic != BOOTROM_MAGIC) { - if (!((magic ^ BOOTROM_MAGIC)&0xffff)) - LOG_ERROR("Incorrect RP2040 BOOT ROM version"); - else - LOG_ERROR("RP2040 BOOT ROM not found"); + + found_rp2040_magic = magic == BOOTROM_RP2040_MAGIC; + found_rp2350_magic = magic == BOOTROM_RP2350_MAGIC; + + if (!(found_rp2040_magic || found_rp2350_magic)) { + LOG_ERROR("RP2040/RP2350 BOOT ROM not found"); return ERROR_FAIL; } /* dereference the table pointer */ uint16_t table_entry; - err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_entry); + err = target_read_u16(target, magic_addr + 4, &table_entry); if (err != ERROR_OK) return err; @@ -82,16 +127,29 @@ static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16 if (err != ERROR_OK) return err; if (entry_tag == tag) { - /* 16 bit symbol is next */ - return target_read_u16(target, table_entry + 2, symbol); + if (found_rp2350_magic) { + uint16_t flags; + /* flags are next */ + err = target_read_u16(target, table_entry + 4, &flags); + if (err != ERROR_OK) + return err; + // + if (flags & RT_ARM_FUNC) { + /* 16 bit symbol */ + return target_read_u16(target, table_entry + 2, symbol); + } + } else { + /* 16 bit symbol is next */ + return target_read_u16(target, table_entry + 2, symbol); + } } - table_entry += 4; + table_entry += found_rp2350_magic ? 6 : 4; } while (entry_tag); return ERROR_FAIL; } static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, - uint16_t func_offset, uint32_t argdata[], unsigned int n_args, unsigned int timeout_ms) + uint16_t func_offset, uint32_t argdata[], unsigned int n_args) { char *regnames[4] = { "r0", "r1", "r2", "r3" }; @@ -103,9 +161,10 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank } target_addr_t stacktop = priv->stack->address + priv->stack->size; - LOG_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args); + LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args); + LOG_DEBUG("Calling on core \"%s\"", target->cmd_name); - struct reg_param args[ARRAY_SIZE(regnames) + 2]; + struct reg_param args[ARRAY_SIZE(regnames) + 12]; struct armv7m_algorithm alg_info; for (unsigned int i = 0; i < n_args; ++i) { @@ -113,14 +172,36 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank buf_set_u32(args[i].value, 0, 32, argdata[i]); } /* Pass function pointer in r7 */ - init_reg_param(&args[n_args], "r7", 32, PARAM_OUT); - buf_set_u32(args[n_args].value, 0, 32, func_offset); - /* Setup stack */ - init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT); - buf_set_u32(args[n_args + 1].value, 0, 32, stacktop); - unsigned int n_reg_params = n_args + 2; /* User arguments + r7 + sp */ - - for (unsigned int i = 0; i < n_reg_params; ++i) + unsigned int extra_args = 0; + init_reg_param(&args[n_args + extra_args], "r7", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, func_offset); + /* Set stack pointer, have seen the caching get confused by the aliases of sp so + take the shotgun approach*/ + init_reg_param(&args[n_args + extra_args], "msp_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "msp_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "psp_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "psp_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "msp", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "psp", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "sp", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + /* Clear stack pointer limits, as they may be above the algorithm stack */ + init_reg_param(&args[n_args + extra_args], "msplim_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + init_reg_param(&args[n_args + extra_args], "psplim_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + init_reg_param(&args[n_args + extra_args], "msplim_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + init_reg_param(&args[n_args + extra_args], "psplim_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + + for (unsigned int i = 0; i < n_args + extra_args; ++i) LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32)); /* Actually call the function */ @@ -129,82 +210,158 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank int err = target_run_algorithm( target, 0, NULL, /* No memory arguments */ - n_reg_params, args, /* User arguments + r7 + sp */ + n_args + extra_args, args, /* User arguments + r7 + SPs */ priv->jump_debug_trampoline, priv->jump_debug_trampoline_end, - timeout_ms, + 3000, /* 3s timeout */ &alg_info ); - - for (unsigned int i = 0; i < n_reg_params; ++i) + for (unsigned int i = 0; i < n_args + extra_args; ++i) destroy_reg_param(&args[i]); - if (err != ERROR_OK) - LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16, func_offset); - + LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset); return err; } -/* Finalize flash write/erase/read ID - * - flush cache - * - enters memory-mapped (XIP) mode to make flash data visible - * - deallocates target ROM func stack if previously allocated - */ -static int rp2040_finalize_stack_free(struct flash_bank *bank) +static int rp2350_init_core(struct target *target, struct rp2040_flash_bank *priv) { - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; + if (!priv->stack) { + LOG_ERROR("no stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - /* Always flush before returning to execute-in-place, to invalidate stale - * cache contents. The flush call also restores regular hardware-controlled - * chip select following a rp2040_flash_exit_xip(). - */ - LOG_DEBUG("Flushing flash cache after write behind"); - int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000); + struct armv7m_algorithm alg_info; + + // copy rcp_init code onto stack, as we don't actually need any stack during the call + if (priv->stack->size < sizeof(rcp_init_code)) { + LOG_ERROR("Working area too small for rcp_init"); + return ERROR_BUF_TOO_SMALL; + } + + // Attempt to reset ACCESSCTRL before running RCP init, in case Secure + // access to SRAM has been blocked. (Also ROM, QMI regs are needed later) + uint32_t accessctrl_lock_reg; + if (target_read_u32(target, ACCESSCTRL_LOCK_OFFSET, &accessctrl_lock_reg) != ERROR_OK) { + LOG_ERROR("Failed to read ACCESSCTRL lock register"); + // Failed to read an APB register which should always be readable from + // any security/privilege level. Something fundamental is wrong. E.g.: + // + // - The debugger is attempting to perform Secure bus accesses on a + // system where Secure debug has been disabled + // - clk_sys or busfabric clock are stopped (try doing a rescue reset) + return ERROR_FAIL; + } + if (accessctrl_lock_reg & ACCESSCTRL_LOCK_DEBUG_BITS) { + LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail.\n"); + } else { + LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET\n"); + target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); + } + + int err = target_write_memory(target, + priv->stack->address, + 1, + sizeof(rcp_init_code), + (const uint8_t *)rcp_init_code + ); if (err != ERROR_OK) { - LOG_ERROR("Failed to flush flash cache"); - /* Intentionally continue after error and try to setup xip anyway */ + LOG_ERROR("Failed to load rcp_init algorithm into RAM\n"); + return ERROR_FAIL; } - LOG_DEBUG("Configuring SSI for execute-in-place"); - err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000); - if (err != ERROR_OK) - LOG_ERROR("Failed to set SSI to XIP mode"); + LOG_DEBUG("Calling rcp_init core \"%s\" code at 0x%" PRIx16 "\n", target->cmd_name, (uint32_t)priv->stack->address); + + /* Actually call the function */ + alg_info.common_magic = ARMV7M_COMMON_MAGIC; + alg_info.core_mode = ARM_MODE_THREAD; + err = target_run_algorithm(target, + 0, NULL, /* No memory arguments */ + 0, NULL, /* No register arguments */ + priv->stack->address, + priv->stack->address + rcp_init_code_bkpt_offset, + 1000, /* 1s timeout */ + &alg_info + ); + if (err != ERROR_OK) { + LOG_ERROR("Failed to invoke rcp_init\n"); + return err; + } + + uint32_t reset_args[1] = { + BOOTROM_STATE_RESET_CURRENT_CORE + }; + if (!priv->jump_bootrom_reset_state) { + LOG_WARNING("RP2350 flash: no bootrom_reset_method\n"); + } else { + err = rp2040_call_rom_func(target, priv, priv->jump_bootrom_reset_state, reset_args, ARRAY_SIZE(reset_args)); + if (err != ERROR_OK) { + LOG_ERROR("RP2040 flash: failed to call reset core state"); + return err; + } + } - target_free_working_area(target, priv->stack); - priv->stack = NULL; return err; } -/* Prepare flash write/erase/read ID - * - allocates a stack for target ROM func - * - switches the SPI interface from memory-mapped mode to direct command mode - * Always pair with a call of rp2040_finalize_stack_free() - * after flash operation finishes or fails. - */ -static int rp2040_stack_grab_and_prep(struct flash_bank *bank) +static int setup_for_rom_call(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; - /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ - const int STACK_SIZE = 256; - int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack); + int err = ERROR_OK; + if (!priv->stack) { + /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ + const int STACK_SIZE = 256; + target_alloc_working_area(bank->target, STACK_SIZE, &priv->stack); + if (err != ERROR_OK) { + LOG_ERROR("Could not allocate stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + // Flash algorithms must run in Secure state + uint32_t dscsr; + (void)target_read_u32(target, DCB_DSCSR, &dscsr); + LOG_DEBUG("DSCSR: %08x\n", dscsr); + if (!(dscsr & DSCSR_CDS)) { + LOG_DEBUG("Setting Current Domain Secure in DSCSR\n"); + (void)target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); + (void)target_read_u32(target, DCB_DSCSR, &dscsr); + LOG_DEBUG("DSCSR*: %08x\n", dscsr); + } + + // hacky RP2350 check + if (target_to_arm(target)->arch == ARM_ARCH_V8M) { + err = rp2350_init_core(target, priv); + if (err != ERROR_OK) { + LOG_ERROR("RP2350 flash: failed to init core"); + return err; + } + } + return err; +} + +static int setup_for_raw_flash_cmd(struct flash_bank *bank) +{ + struct rp2040_flash_bank *priv = bank->driver_priv; + int err = setup_for_rom_call(bank); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0); if (err != ERROR_OK) { - LOG_ERROR("Could not allocate stack for flash programming code"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + LOG_ERROR("RP2040 flash: failed to setup for rom call"); + return err; } LOG_DEBUG("Connecting internal flash"); - err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0); if (err != ERROR_OK) { - LOG_ERROR("Failed to connect internal flash"); + LOG_ERROR("RP2040 flash: failed to connect internal flash"); return err; } LOG_DEBUG("Kicking flash out of XIP mode"); - err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_exit_xip, NULL, 0); if (err != ERROR_OK) { - LOG_ERROR("Failed to exit flash XIP mode"); + LOG_ERROR("RP2040 flash: failed to exit flash XIP mode"); return err; } @@ -217,27 +374,17 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; + struct working_area *bounce; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - struct working_area *bounce = NULL; - - int err = rp2040_stack_grab_and_prep(bank); + int err = setup_for_raw_flash_cmd(bank); if (err != ERROR_OK) - goto cleanup; - - unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize; - /* We try to allocate working area rounded down to device page size, - * al least 1 page, at most the write data size - */ - unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count); - err = target_alloc_working_area(target, chunk_size, &bounce); - if (err != ERROR_OK) { + return err; + + // Allocate as much memory as possible, rounded down to a whole number of flash pages + const unsigned int chunk_size = target_get_working_area_avail(target) & ~0xffu; + if (chunk_size == 0 || target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) { LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); - goto cleanup; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); @@ -255,8 +402,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui bounce->address, /* data */ write_size /* count */ }; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, - args, ARRAY_SIZE(args), 3000); + err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args)); if (err != ERROR_OK) { LOG_ERROR("Failed to invoke flash programming code on target"); break; @@ -266,40 +412,44 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui offset += write_size; count -= write_size; } - -cleanup: target_free_working_area(target, bounce); - rp2040_finalize_stack_free(bank); + if (err != ERROR_OK) + return err; + /* Flash is successfully programmed. We can now do a bit of poking to make the flash + contents visible to us via memory-mapped (XIP) interface in the 0x1... memory region */ + LOG_DEBUG("Flushing flash cache after write behind"); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0); + if (err != ERROR_OK) { + LOG_ERROR("RP2040 write: failed to flush flash cache"); + return err; + } + LOG_DEBUG("Configuring SSI for execute-in-place"); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_enter_cmd_xip, NULL, 0); + if (err != ERROR_OK) + LOG_ERROR("RP2040 write: failed to flush flash cache"); return err; } static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - uint32_t start_addr = bank->sectors[first].offset; 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); - int err = rp2040_stack_grab_and_prep(bank); + int err = setup_for_raw_flash_cmd(bank); if (err != ERROR_OK) - goto cleanup; + return err; LOG_DEBUG("Remote call flash_range_erase"); uint32_t args[4] = { bank->sectors[first].offset, /* addr */ bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */ - priv->dev->sectorsize, /* block_size */ - priv->dev->erase_cmd /* block_cmd */ + 65536, /* block_size */ + 0xd8 /* block_cmd */ }; /* @@ -309,15 +459,10 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and - an optional larger "block" (size and command provided in args). + an optional larger "block" (size and command provided in args). OpenOCD's spi.c only uses "block" sizes. */ - unsigned int timeout_ms = 2000 * (last - first) + 1000; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase, - args, ARRAY_SIZE(args), timeout_ms); - -cleanup: - rp2040_finalize_stack_free(bank); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); return err; } @@ -325,67 +470,11 @@ cleanup: /* ----------------------------------------------------------------------------- Driver probing etc */ -static int rp2040_ssel_active(struct target *target, bool active) -{ - const target_addr_t qspi_ctrl_addr = 0x4001800c; - const uint32_t qspi_ctrl_outover_low = 2UL << 8; - const uint32_t qspi_ctrl_outover_high = 3UL << 8; - uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high; - uint32_t val; - - int err = target_read_u32(target, qspi_ctrl_addr, &val); - if (err != ERROR_OK) - return err; - - val = (val & ~qspi_ctrl_outover_high) | state; - - err = target_write_u32(target, qspi_ctrl_addr, val); - if (err != ERROR_OK) - return err; - - return ERROR_OK; -} - -static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid) -{ - uint32_t device_id = 0; - const target_addr_t ssi_dr0 = 0x18000060; - - int err = rp2040_ssel_active(target, true); - - /* write RDID request into SPI peripheral's FIFO */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) - err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID); - - /* by this time, there is a receive FIFO entry for every write */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) { - uint32_t status; - err = target_read_u32(target, ssi_dr0, &status); - - device_id >>= 8; - device_id |= (status & 0xFF) << 24; - } - - if (err == ERROR_OK) - *devid = device_id >> 8; - - int err2 = rp2040_ssel_active(target, false); - if (err2 != ERROR_OK) - LOG_ERROR("SSEL inactive failed"); - - return err; -} - static int rp2040_flash_probe(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline); if (err != ERROR_OK) { LOG_ERROR("Debug trampoline not found in RP2040 ROM."); @@ -417,6 +506,7 @@ static int rp2040_flash_probe(struct flash_bank *bank) LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM."); return err; } + LOG_WARNING("GOT FLASH ERASE AT %08x\n", (int)priv->jump_flash_range_erase); err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program); if (err != ERROR_OK) { @@ -436,50 +526,25 @@ static int rp2040_flash_probe(struct flash_bank *bank) return err; } - if (bank->size) { - /* size overridden, suppress reading SPI flash ID */ - priv->dev = &rp2040_default_spi_device; - LOG_DEBUG("SPI flash autodetection disabled, using configured size"); - - } else { - /* zero bank size in cfg, read SPI flash ID and autodetect */ - err = rp2040_stack_grab_and_prep(bank); - - uint32_t device_id = 0; - if (err == ERROR_OK) - err = rp2040_spi_read_flash_id(target, &device_id); - - rp2040_finalize_stack_free(bank); - - if (err != ERROR_OK) - return err; - - /* search for a SPI flash Device ID match */ - priv->dev = NULL; - for (const struct flash_device *p = flash_devices; p->name ; p++) - if (p->device_id == device_id) { - priv->dev = p; - break; - } - - if (!priv->dev) { - LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id); - return ERROR_FAIL; - } - LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")", - priv->dev->name, priv->dev->device_id); - - bank->size = priv->dev->size_in_bytes; + err = rp2040_lookup_symbol(target, FUNC_BOOTROM_STATE_RESET, &priv->jump_bootrom_reset_state); + if (err != ERROR_OK) { + priv->jump_bootrom_reset_state = 0; +// LOG_ERROR("Function FUNC_BOOTROM_STATE_RESET not found in RP2040 ROM."); +// return err; } /* the Boot ROM flash_range_program() routine requires page alignment */ - bank->write_start_alignment = priv->dev->pagesize; - bank->write_end_alignment = priv->dev->pagesize; + bank->write_start_alignment = 256; + bank->write_end_alignment = 256; + + // Max size -- up to two devices (two chip selects) in adjacent 24-bit address windows + bank->size = 32 * 1024 * 1024; + + bank->num_sectors = bank->size / 4096; - bank->num_sectors = bank->size / priv->dev->sectorsize; - LOG_INFO("RP2040 B0 Flash Probe: %" PRIu32 " bytes @" TARGET_ADDR_FMT ", in %u sectors\n", + LOG_INFO("RP2040 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n", bank->size, bank->base, bank->num_sectors); - bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors); + bank->sectors = alloc_block_array(0, 4096, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; --