flash/nor/rp2040: fix memory leak of target stack workarea
[openocd.git] / src / flash / nor / rp2040.c
blob1c57424f914b0353ddd85671afc7a16cb3807fbe
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include "imp.h"
8 #include <helper/binarybuffer.h>
9 #include <target/algorithm.h>
10 #include <target/armv7m.h>
11 #include "spi.h"
13 /* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010
14 Your gdbinit should load the bootrom.elf if appropriate */
16 /* this is 'M' 'u', 1 (version) */
17 #define BOOTROM_MAGIC 0x01754d
18 #define BOOTROM_MAGIC_ADDR 0x00000010
20 /* Call a ROM function via the debug trampoline
21 Up to four arguments passed in r0...r3 as per ABI
22 Function address is passed in r7
23 the trampoline is needed because OpenOCD "algorithm" code insists on sw breakpoints. */
25 #define MAKE_TAG(a, b) (((b)<<8) | a)
26 #define FUNC_DEBUG_TRAMPOLINE MAKE_TAG('D', 'T')
27 #define FUNC_DEBUG_TRAMPOLINE_END MAKE_TAG('D', 'E')
28 #define FUNC_FLASH_EXIT_XIP MAKE_TAG('E', 'X')
29 #define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F')
30 #define FUNC_FLASH_RANGE_ERASE MAKE_TAG('R', 'E')
31 #define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P')
32 #define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C')
33 #define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X')
35 struct rp2040_flash_bank {
36 /* flag indicating successful flash probe */
37 bool probed;
38 /* stack used by Boot ROM calls */
39 struct working_area *stack;
40 /* function jump table populated by rp2040_flash_probe() */
41 uint16_t jump_debug_trampoline;
42 uint16_t jump_debug_trampoline_end;
43 uint16_t jump_flash_exit_xip;
44 uint16_t jump_connect_internal_flash;
45 uint16_t jump_flash_range_erase;
46 uint16_t jump_flash_range_program;
47 uint16_t jump_flush_cache;
48 uint16_t jump_enter_cmd_xip;
49 /* detected model of SPI flash */
50 const struct flash_device *dev;
53 static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol)
55 uint32_t magic;
56 int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic);
57 if (err != ERROR_OK)
58 return err;
60 magic &= 0xffffff; /* ignore bootrom version */
61 if (magic != BOOTROM_MAGIC) {
62 if (!((magic ^ BOOTROM_MAGIC)&0xffff))
63 LOG_ERROR("Incorrect RP2040 BOOT ROM version");
64 else
65 LOG_ERROR("RP2040 BOOT ROM not found");
66 return ERROR_FAIL;
69 /* dereference the table pointer */
70 uint16_t table_entry;
71 err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_entry);
72 if (err != ERROR_OK)
73 return err;
75 uint16_t entry_tag;
76 do {
77 err = target_read_u16(target, table_entry, &entry_tag);
78 if (err != ERROR_OK)
79 return err;
80 if (entry_tag == tag) {
81 /* 16 bit symbol is next */
82 return target_read_u16(target, table_entry + 2, symbol);
84 table_entry += 4;
85 } while (entry_tag);
86 return ERROR_FAIL;
89 static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv,
90 uint16_t func_offset, uint32_t argdata[], unsigned int n_args)
92 char *regnames[4] = { "r0", "r1", "r2", "r3" };
94 assert(n_args <= ARRAY_SIZE(regnames)); /* only allow register arguments */
96 if (!priv->stack) {
97 LOG_ERROR("no stack for flash programming code");
98 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
100 target_addr_t stacktop = priv->stack->address + priv->stack->size;
102 LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args);
103 LOG_DEBUG("Calling on core \"%s\"", target->cmd_name);
105 struct reg_param args[ARRAY_SIZE(regnames) + 2];
106 struct armv7m_algorithm alg_info;
108 for (unsigned int i = 0; i < n_args; ++i) {
109 init_reg_param(&args[i], regnames[i], 32, PARAM_OUT);
110 buf_set_u32(args[i].value, 0, 32, argdata[i]);
112 /* Pass function pointer in r7 */
113 init_reg_param(&args[n_args], "r7", 32, PARAM_OUT);
114 buf_set_u32(args[n_args].value, 0, 32, func_offset);
115 init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT);
116 buf_set_u32(args[n_args + 1].value, 0, 32, stacktop);
119 for (unsigned int i = 0; i < n_args + 2; ++i)
120 LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32));
122 /* Actually call the function */
123 alg_info.common_magic = ARMV7M_COMMON_MAGIC;
124 alg_info.core_mode = ARM_MODE_THREAD;
125 int err = target_run_algorithm(
126 target,
127 0, NULL, /* No memory arguments */
128 n_args + 1, args, /* User arguments + r7 */
129 priv->jump_debug_trampoline, priv->jump_debug_trampoline_end,
130 3000, /* 3s timeout */
131 &alg_info
133 for (unsigned int i = 0; i < n_args + 2; ++i)
134 destroy_reg_param(&args[i]);
135 if (err != ERROR_OK)
136 LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset);
137 return err;
141 /* Finalize flash write/erase/read ID
142 * - flush cache
143 * - enters memory-mapped (XIP) mode to make flash data visible
144 * - deallocates target ROM func stack if previously allocated
146 static int rp2040_finalize_stack_free(struct flash_bank *bank)
148 struct rp2040_flash_bank *priv = bank->driver_priv;
149 struct target *target = bank->target;
151 /* Always flush before returning to execute-in-place, to invalidate stale
152 * cache contents. The flush call also restores regular hardware-controlled
153 * chip select following a rp2040_flash_exit_xip().
155 LOG_DEBUG("Flushing flash cache after write behind");
156 int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0);
157 if (err != ERROR_OK) {
158 LOG_ERROR("Failed to flush flash cache");
159 /* Intentionally continue after error and try to setup xip anyway */
162 LOG_DEBUG("Configuring SSI for execute-in-place");
163 err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0);
164 if (err != ERROR_OK)
165 LOG_ERROR("Failed to set SSI to XIP mode");
167 target_free_working_area(target, priv->stack);
168 priv->stack = NULL;
169 return err;
172 /* Prepare flash write/erase/read ID
173 * - allocates a stack for target ROM func
174 * - switches the SPI interface from memory-mapped mode to direct command mode
175 * Always pair with a call of rp2040_finalize_stack_free()
176 * after flash operation finishes or fails.
178 static int rp2040_stack_grab_and_prep(struct flash_bank *bank)
180 struct rp2040_flash_bank *priv = bank->driver_priv;
181 struct target *target = bank->target;
183 /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
184 const int STACK_SIZE = 256;
185 int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack);
186 if (err != ERROR_OK) {
187 LOG_ERROR("Could not allocate stack for flash programming code");
188 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
191 LOG_DEBUG("Connecting internal flash");
192 err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0);
193 if (err != ERROR_OK) {
194 LOG_ERROR("Failed to connect internal flash");
195 return err;
198 LOG_DEBUG("Kicking flash out of XIP mode");
199 err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0);
200 if (err != ERROR_OK) {
201 LOG_ERROR("Failed to exit flash XIP mode");
202 return err;
205 return ERROR_OK;
208 static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
210 LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset);
212 struct rp2040_flash_bank *priv = bank->driver_priv;
213 struct target *target = bank->target;
214 struct working_area *bounce = NULL;
216 int err = rp2040_stack_grab_and_prep(bank);
217 if (err != ERROR_OK)
218 goto cleanup;
220 const unsigned int chunk_size = target_get_working_area_avail(target);
221 err = target_alloc_working_area(target, chunk_size, &bounce);
222 if (err != ERROR_OK) {
223 LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
224 goto cleanup;
227 LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
229 while (count > 0) {
230 uint32_t write_size = count > chunk_size ? chunk_size : count;
231 LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset);
232 err = target_write_buffer(target, bounce->address, write_size, buffer);
233 if (err != ERROR_OK) {
234 LOG_ERROR("Could not load data into target bounce buffer");
235 break;
237 uint32_t args[3] = {
238 offset, /* addr */
239 bounce->address, /* data */
240 write_size /* count */
242 err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args));
243 if (err != ERROR_OK) {
244 LOG_ERROR("Failed to invoke flash programming code on target");
245 break;
248 buffer += write_size;
249 offset += write_size;
250 count -= write_size;
253 cleanup:
254 target_free_working_area(target, bounce);
256 rp2040_finalize_stack_free(bank);
258 return err;
261 static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
263 struct rp2040_flash_bank *priv = bank->driver_priv;
264 uint32_t start_addr = bank->sectors[first].offset;
265 uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
266 LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
268 int err = rp2040_stack_grab_and_prep(bank);
269 if (err != ERROR_OK)
270 goto cleanup;
272 LOG_DEBUG("Remote call flash_range_erase");
274 uint32_t args[4] = {
275 bank->sectors[first].offset, /* addr */
276 bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */
277 priv->dev->sectorsize, /* block_size */
278 priv->dev->erase_cmd /* block_cmd */
282 The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3:
283 https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
284 and the particular source code for said Boot ROM function can be found here:
285 https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
287 In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and
288 an optional larger "block" (size and command provided in args).
291 err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
293 cleanup:
294 rp2040_finalize_stack_free(bank);
296 return err;
299 /* -----------------------------------------------------------------------------
300 Driver probing etc */
302 static int rp2040_ssel_active(struct target *target, bool active)
304 const target_addr_t qspi_ctrl_addr = 0x4001800c;
305 const uint32_t qspi_ctrl_outover_low = 2UL << 8;
306 const uint32_t qspi_ctrl_outover_high = 3UL << 8;
307 uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high;
308 uint32_t val;
310 int err = target_read_u32(target, qspi_ctrl_addr, &val);
311 if (err != ERROR_OK)
312 return err;
314 val = (val & ~qspi_ctrl_outover_high) | state;
316 err = target_write_u32(target, qspi_ctrl_addr, val);
317 if (err != ERROR_OK)
318 return err;
320 return ERROR_OK;
323 static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid)
325 uint32_t device_id = 0;
326 const target_addr_t ssi_dr0 = 0x18000060;
328 int err = rp2040_ssel_active(target, true);
330 /* write RDID request into SPI peripheral's FIFO */
331 for (int count = 0; (count < 4) && (err == ERROR_OK); count++)
332 err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID);
334 /* by this time, there is a receive FIFO entry for every write */
335 for (int count = 0; (count < 4) && (err == ERROR_OK); count++) {
336 uint32_t status;
337 err = target_read_u32(target, ssi_dr0, &status);
339 device_id >>= 8;
340 device_id |= (status & 0xFF) << 24;
343 if (err == ERROR_OK)
344 *devid = device_id >> 8;
346 int err2 = rp2040_ssel_active(target, false);
347 if (err2 != ERROR_OK)
348 LOG_ERROR("SSEL inactive failed");
350 return err;
353 static int rp2040_flash_probe(struct flash_bank *bank)
355 struct rp2040_flash_bank *priv = bank->driver_priv;
356 struct target *target = bank->target;
358 int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline);
359 if (err != ERROR_OK) {
360 LOG_ERROR("Debug trampoline not found in RP2040 ROM.");
361 return err;
363 priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */
365 err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end);
366 if (err != ERROR_OK) {
367 LOG_ERROR("Debug trampoline end not found in RP2040 ROM.");
368 return err;
370 priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */
372 err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip);
373 if (err != ERROR_OK) {
374 LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM.");
375 return err;
378 err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash);
379 if (err != ERROR_OK) {
380 LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM.");
381 return err;
384 err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase);
385 if (err != ERROR_OK) {
386 LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM.");
387 return err;
390 err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program);
391 if (err != ERROR_OK) {
392 LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM.");
393 return err;
396 err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache);
397 if (err != ERROR_OK) {
398 LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM.");
399 return err;
402 err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip);
403 if (err != ERROR_OK) {
404 LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM.");
405 return err;
408 err = rp2040_stack_grab_and_prep(bank);
410 uint32_t device_id = 0;
411 if (err == ERROR_OK)
412 err = rp2040_spi_read_flash_id(target, &device_id);
414 rp2040_finalize_stack_free(bank);
416 if (err != ERROR_OK)
417 return err;
419 /* search for a SPI flash Device ID match */
420 priv->dev = NULL;
421 for (const struct flash_device *p = flash_devices; p->name ; p++)
422 if (p->device_id == device_id) {
423 priv->dev = p;
424 break;
427 if (!priv->dev) {
428 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id);
429 return ERROR_FAIL;
432 LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
433 priv->dev->name, priv->dev->device_id);
435 /* the Boot ROM flash_range_program() routine requires page alignment */
436 bank->write_start_alignment = priv->dev->pagesize;
437 bank->write_end_alignment = priv->dev->pagesize;
439 bank->size = priv->dev->size_in_bytes;
441 bank->num_sectors = bank->size / priv->dev->sectorsize;
442 LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n",
443 bank->size, bank->base, bank->num_sectors);
444 bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
445 if (!bank->sectors)
446 return ERROR_FAIL;
448 if (err == ERROR_OK)
449 priv->probed = true;
451 return err;
454 static int rp2040_flash_auto_probe(struct flash_bank *bank)
456 struct rp2040_flash_bank *priv = bank->driver_priv;
458 if (priv->probed)
459 return ERROR_OK;
461 return rp2040_flash_probe(bank);
464 static void rp2040_flash_free_driver_priv(struct flash_bank *bank)
466 free(bank->driver_priv);
467 bank->driver_priv = NULL;
470 /* -----------------------------------------------------------------------------
471 Driver boilerplate */
473 FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
475 struct rp2040_flash_bank *priv;
476 priv = malloc(sizeof(struct rp2040_flash_bank));
477 priv->probed = false;
479 /* Set up driver_priv */
480 bank->driver_priv = priv;
482 return ERROR_OK;
485 struct flash_driver rp2040_flash = {
486 .name = "rp2040_flash",
487 .flash_bank_command = rp2040_flash_bank_command,
488 .erase = rp2040_flash_erase,
489 .write = rp2040_flash_write,
490 .read = default_flash_read,
491 .probe = rp2040_flash_probe,
492 .auto_probe = rp2040_flash_auto_probe,
493 .erase_check = default_flash_blank_check,
494 .free_driver_priv = rp2040_flash_free_driver_priv