flash/nor/rp2040: check target halted before flash operation
[openocd.git] / src / flash / nor / rp2040.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #include "imp.h"
8 #include <helper/binarybuffer.h>
9 #include <target/algorithm.h>
10 #include <target/armv7m.h>
11 #include "spi.h"
12
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 */
15
16 /* this is 'M' 'u', 1 (version) */
17 #define BOOTROM_MAGIC 0x01754d
18 #define BOOTROM_MAGIC_ADDR 0x00000010
19
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. */
24
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')
34
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;
51 };
52
53 static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol)
54 {
55 uint32_t magic;
56 int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic);
57 if (err != ERROR_OK)
58 return err;
59
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;
67 }
68
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;
74
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);
83 }
84 table_entry += 4;
85 } while (entry_tag);
86 return ERROR_FAIL;
87 }
88
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, int timeout_ms)
91 {
92 char *regnames[4] = { "r0", "r1", "r2", "r3" };
93
94 assert(n_args <= ARRAY_SIZE(regnames)); /* only allow register arguments */
95
96 if (!priv->stack) {
97 LOG_ERROR("no stack for flash programming code");
98 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
99 }
100 target_addr_t stacktop = priv->stack->address + priv->stack->size;
101
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);
104
105 struct reg_param args[ARRAY_SIZE(regnames) + 2];
106 struct armv7m_algorithm alg_info;
107
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]);
111 }
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);
117
118
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));
121
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 timeout_ms,
131 &alg_info
132 );
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;
138
139 }
140
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
145 */
146 static int rp2040_finalize_stack_free(struct flash_bank *bank)
147 {
148 struct rp2040_flash_bank *priv = bank->driver_priv;
149 struct target *target = bank->target;
150
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().
154 */
155 LOG_DEBUG("Flushing flash cache after write behind");
156 int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000);
157 if (err != ERROR_OK) {
158 LOG_ERROR("Failed to flush flash cache");
159 /* Intentionally continue after error and try to setup xip anyway */
160 }
161
162 LOG_DEBUG("Configuring SSI for execute-in-place");
163 err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000);
164 if (err != ERROR_OK)
165 LOG_ERROR("Failed to set SSI to XIP mode");
166
167 target_free_working_area(target, priv->stack);
168 priv->stack = NULL;
169 return err;
170 }
171
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.
177 */
178 static int rp2040_stack_grab_and_prep(struct flash_bank *bank)
179 {
180 struct rp2040_flash_bank *priv = bank->driver_priv;
181 struct target *target = bank->target;
182
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;
189 }
190
191 LOG_DEBUG("Connecting internal flash");
192 err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000);
193 if (err != ERROR_OK) {
194 LOG_ERROR("Failed to connect internal flash");
195 return err;
196 }
197
198 LOG_DEBUG("Kicking flash out of XIP mode");
199 err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000);
200 if (err != ERROR_OK) {
201 LOG_ERROR("Failed to exit flash XIP mode");
202 return err;
203 }
204
205 return ERROR_OK;
206 }
207
208 static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
209 {
210 LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset);
211
212 struct rp2040_flash_bank *priv = bank->driver_priv;
213 struct target *target = bank->target;
214
215 if (target->state != TARGET_HALTED) {
216 LOG_ERROR("Target not halted");
217 return ERROR_TARGET_NOT_HALTED;
218 }
219
220 struct working_area *bounce = NULL;
221
222 int err = rp2040_stack_grab_and_prep(bank);
223 if (err != ERROR_OK)
224 goto cleanup;
225
226 unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize;
227 /* We try to allocate working area rounded down to device page size,
228 * al least 1 page, at most the write data size
229 */
230 unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count);
231 err = target_alloc_working_area(target, chunk_size, &bounce);
232 if (err != ERROR_OK) {
233 LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
234 goto cleanup;
235 }
236
237 LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
238
239 while (count > 0) {
240 uint32_t write_size = count > chunk_size ? chunk_size : count;
241 LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset);
242 err = target_write_buffer(target, bounce->address, write_size, buffer);
243 if (err != ERROR_OK) {
244 LOG_ERROR("Could not load data into target bounce buffer");
245 break;
246 }
247 uint32_t args[3] = {
248 offset, /* addr */
249 bounce->address, /* data */
250 write_size /* count */
251 };
252 err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program,
253 args, ARRAY_SIZE(args), 3000);
254 if (err != ERROR_OK) {
255 LOG_ERROR("Failed to invoke flash programming code on target");
256 break;
257 }
258
259 buffer += write_size;
260 offset += write_size;
261 count -= write_size;
262 }
263
264 cleanup:
265 target_free_working_area(target, bounce);
266
267 rp2040_finalize_stack_free(bank);
268
269 return err;
270 }
271
272 static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
273 {
274 struct rp2040_flash_bank *priv = bank->driver_priv;
275 struct target *target = bank->target;
276
277 if (target->state != TARGET_HALTED) {
278 LOG_ERROR("Target not halted");
279 return ERROR_TARGET_NOT_HALTED;
280 }
281
282 uint32_t start_addr = bank->sectors[first].offset;
283 uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
284 LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
285
286 int err = rp2040_stack_grab_and_prep(bank);
287 if (err != ERROR_OK)
288 goto cleanup;
289
290 LOG_DEBUG("Remote call flash_range_erase");
291
292 uint32_t args[4] = {
293 bank->sectors[first].offset, /* addr */
294 bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */
295 priv->dev->sectorsize, /* block_size */
296 priv->dev->erase_cmd /* block_cmd */
297 };
298
299 /*
300 The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3:
301 https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
302 and the particular source code for said Boot ROM function can be found here:
303 https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
304
305 In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and
306 an optional larger "block" (size and command provided in args).
307 */
308
309 int timeout_ms = 2000 * (last - first) + 1000;
310 err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase,
311 args, ARRAY_SIZE(args), timeout_ms);
312
313 cleanup:
314 rp2040_finalize_stack_free(bank);
315
316 return err;
317 }
318
319 /* -----------------------------------------------------------------------------
320 Driver probing etc */
321
322 static int rp2040_ssel_active(struct target *target, bool active)
323 {
324 const target_addr_t qspi_ctrl_addr = 0x4001800c;
325 const uint32_t qspi_ctrl_outover_low = 2UL << 8;
326 const uint32_t qspi_ctrl_outover_high = 3UL << 8;
327 uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high;
328 uint32_t val;
329
330 int err = target_read_u32(target, qspi_ctrl_addr, &val);
331 if (err != ERROR_OK)
332 return err;
333
334 val = (val & ~qspi_ctrl_outover_high) | state;
335
336 err = target_write_u32(target, qspi_ctrl_addr, val);
337 if (err != ERROR_OK)
338 return err;
339
340 return ERROR_OK;
341 }
342
343 static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid)
344 {
345 uint32_t device_id = 0;
346 const target_addr_t ssi_dr0 = 0x18000060;
347
348 int err = rp2040_ssel_active(target, true);
349
350 /* write RDID request into SPI peripheral's FIFO */
351 for (int count = 0; (count < 4) && (err == ERROR_OK); count++)
352 err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID);
353
354 /* by this time, there is a receive FIFO entry for every write */
355 for (int count = 0; (count < 4) && (err == ERROR_OK); count++) {
356 uint32_t status;
357 err = target_read_u32(target, ssi_dr0, &status);
358
359 device_id >>= 8;
360 device_id |= (status & 0xFF) << 24;
361 }
362
363 if (err == ERROR_OK)
364 *devid = device_id >> 8;
365
366 int err2 = rp2040_ssel_active(target, false);
367 if (err2 != ERROR_OK)
368 LOG_ERROR("SSEL inactive failed");
369
370 return err;
371 }
372
373 static int rp2040_flash_probe(struct flash_bank *bank)
374 {
375 struct rp2040_flash_bank *priv = bank->driver_priv;
376 struct target *target = bank->target;
377
378 if (target->state != TARGET_HALTED) {
379 LOG_ERROR("Target not halted");
380 return ERROR_TARGET_NOT_HALTED;
381 }
382
383 int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline);
384 if (err != ERROR_OK) {
385 LOG_ERROR("Debug trampoline not found in RP2040 ROM.");
386 return err;
387 }
388 priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */
389
390 err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end);
391 if (err != ERROR_OK) {
392 LOG_ERROR("Debug trampoline end not found in RP2040 ROM.");
393 return err;
394 }
395 priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */
396
397 err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip);
398 if (err != ERROR_OK) {
399 LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM.");
400 return err;
401 }
402
403 err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash);
404 if (err != ERROR_OK) {
405 LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM.");
406 return err;
407 }
408
409 err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase);
410 if (err != ERROR_OK) {
411 LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM.");
412 return err;
413 }
414
415 err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program);
416 if (err != ERROR_OK) {
417 LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM.");
418 return err;
419 }
420
421 err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache);
422 if (err != ERROR_OK) {
423 LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM.");
424 return err;
425 }
426
427 err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip);
428 if (err != ERROR_OK) {
429 LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM.");
430 return err;
431 }
432
433 err = rp2040_stack_grab_and_prep(bank);
434
435 uint32_t device_id = 0;
436 if (err == ERROR_OK)
437 err = rp2040_spi_read_flash_id(target, &device_id);
438
439 rp2040_finalize_stack_free(bank);
440
441 if (err != ERROR_OK)
442 return err;
443
444 /* search for a SPI flash Device ID match */
445 priv->dev = NULL;
446 for (const struct flash_device *p = flash_devices; p->name ; p++)
447 if (p->device_id == device_id) {
448 priv->dev = p;
449 break;
450 }
451
452 if (!priv->dev) {
453 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id);
454 return ERROR_FAIL;
455 }
456
457 LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
458 priv->dev->name, priv->dev->device_id);
459
460 /* the Boot ROM flash_range_program() routine requires page alignment */
461 bank->write_start_alignment = priv->dev->pagesize;
462 bank->write_end_alignment = priv->dev->pagesize;
463
464 bank->size = priv->dev->size_in_bytes;
465
466 bank->num_sectors = bank->size / priv->dev->sectorsize;
467 LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n",
468 bank->size, bank->base, bank->num_sectors);
469 bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
470 if (!bank->sectors)
471 return ERROR_FAIL;
472
473 if (err == ERROR_OK)
474 priv->probed = true;
475
476 return err;
477 }
478
479 static int rp2040_flash_auto_probe(struct flash_bank *bank)
480 {
481 struct rp2040_flash_bank *priv = bank->driver_priv;
482
483 if (priv->probed)
484 return ERROR_OK;
485
486 return rp2040_flash_probe(bank);
487 }
488
489 static void rp2040_flash_free_driver_priv(struct flash_bank *bank)
490 {
491 free(bank->driver_priv);
492 bank->driver_priv = NULL;
493 }
494
495 /* -----------------------------------------------------------------------------
496 Driver boilerplate */
497
498 FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
499 {
500 struct rp2040_flash_bank *priv;
501 priv = malloc(sizeof(struct rp2040_flash_bank));
502 priv->probed = false;
503
504 /* Set up driver_priv */
505 bank->driver_priv = priv;
506
507 return ERROR_OK;
508 }
509
510 struct flash_driver rp2040_flash = {
511 .name = "rp2040_flash",
512 .flash_bank_command = rp2040_flash_bank_command,
513 .erase = rp2040_flash_erase,
514 .write = rp2040_flash_write,
515 .read = default_flash_read,
516 .probe = rp2040_flash_probe,
517 .auto_probe = rp2040_flash_auto_probe,
518 .erase_check = default_flash_blank_check,
519 .free_driver_priv = rp2040_flash_free_driver_priv
520 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)