flash/nor/rp2040: use LOG_TARGET_xxx to show core name
[fw/openocd] / src / flash / nor / rp2040.c
index 667498ca328c2d9dff3833107b29fb4beb13b014..675f431b159e14bfdc1508acaab6bb861ec2d559 100644 (file)
@@ -87,7 +87,7 @@ static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16
 }
 
 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)
+               uint16_t func_offset, uint32_t argdata[], unsigned int n_args, int timeout_ms)
 {
        char *regnames[4] = { "r0", "r1", "r2", "r3" };
 
@@ -99,8 +99,7 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank
        }
        target_addr_t stacktop = priv->stack->address + priv->stack->size;
 
-       LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args);
-       LOG_DEBUG("Calling on core \"%s\"", target->cmd_name);
+       LOG_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args);
 
        struct reg_param args[ARRAY_SIZE(regnames) + 2];
        struct armv7m_algorithm alg_info;
@@ -127,7 +126,7 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank
                0, NULL,          /* No memory arguments */
                n_args + 1, args, /* User arguments + r7 */
                priv->jump_debug_trampoline, priv->jump_debug_trampoline_end,
-               3000, /* 3s timeout */
+               timeout_ms,
                &alg_info
        );
        for (unsigned int i = 0; i < n_args + 2; ++i)
@@ -138,29 +137,67 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank
 
 }
 
-static int stack_grab_and_prep(struct flash_bank *bank)
+/* 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)
 {
        struct rp2040_flash_bank *priv = bank->driver_priv;
+       struct target *target = bank->target;
+
+       /* 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);
+       if (err != ERROR_OK) {
+               LOG_ERROR("Failed to flush flash cache");
+               /* Intentionally continue after error and try to setup xip anyway */
+       }
+
+       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");
+
+       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)
+{
+       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(bank->target, STACK_SIZE, &priv->stack);
+       int err = target_alloc_working_area(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;
        }
 
        LOG_DEBUG("Connecting internal flash");
-       err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0);
+       err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000);
        if (err != ERROR_OK) {
-               LOG_ERROR("RP2040 erase: failed to connect internal flash");
+               LOG_ERROR("Failed to connect internal flash");
                return err;
        }
 
        LOG_DEBUG("Kicking flash out of XIP mode");
-       err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_exit_xip, NULL, 0);
+       err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000);
        if (err != ERROR_OK) {
-               LOG_ERROR("RP2040 erase: failed to exit flash XIP mode");
+               LOG_ERROR("Failed to exit flash XIP mode");
                return err;
        }
 
@@ -173,16 +210,27 @@ 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;
 
-       int err = stack_grab_and_prep(bank);
-       if (err != ERROR_OK)
-               return err;
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       struct working_area *bounce = NULL;
 
-       const unsigned int chunk_size = target_get_working_area_avail(target);
-       if (target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) {
+       int err = rp2040_stack_grab_and_prep(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) {
                LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto cleanup;
        }
 
        LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
@@ -200,7 +248,8 @@ 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));
+               err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program,
+                                                                args, ARRAY_SIZE(args), 3000);
                if (err != ERROR_OK) {
                        LOG_ERROR("Failed to invoke flash programming code on target");
                        break;
@@ -210,36 +259,32 @@ 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);
 
-       if (err != ERROR_OK)
-               return err;
+       rp2040_finalize_stack_free(bank);
 
-       /* 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 = stack_grab_and_prep(bank);
+       int err = rp2040_stack_grab_and_prep(bank);
        if (err != ERROR_OK)
-               return err;
+               goto cleanup;
 
        LOG_DEBUG("Remote call flash_range_erase");
 
@@ -257,10 +302,15 @@ 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).  OpenOCD's spi.c only uses "block" sizes.
+       an optional larger "block" (size and command provided in args).
        */
 
-       err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
+       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);
 
        return err;
 }
@@ -289,11 +339,46 @@ static int rp2040_ssel_active(struct target *target, bool active)
        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.");
@@ -344,34 +429,16 @@ static int rp2040_flash_probe(struct flash_bank *bank)
                return err;
        }
 
-       err = stack_grab_and_prep(bank);
-       if (err != ERROR_OK)
-               return err;
+       err = rp2040_stack_grab_and_prep(bank);
 
        uint32_t device_id = 0;
-       const target_addr_t ssi_dr0 = 0x18000060;
-
-       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);
+       if (err == ERROR_OK)
+               err = rp2040_spi_read_flash_id(target, &device_id);
 
-               device_id >>= 8;
-               device_id |= (status & 0xFF) << 24;
-       }
-       device_id >>= 8;
+       rp2040_finalize_stack_free(bank);
 
-       err = rp2040_ssel_active(target, false);
-       if (err != ERROR_OK) {
-               LOG_ERROR("SSEL inactive failed");
+       if (err != ERROR_OK)
                return err;
-       }
 
        /* search for a SPI flash Device ID match */
        priv->dev = NULL;