675f431b159e14bfdc1508acaab6bb861ec2d559
[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_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args);
103
104 struct reg_param args[ARRAY_SIZE(regnames) + 2];
105 struct armv7m_algorithm alg_info;
106
107 for (unsigned int i = 0; i < n_args; ++i) {
108 init_reg_param(&args[i], regnames[i], 32, PARAM_OUT);
109 buf_set_u32(args[i].value, 0, 32, argdata[i]);
110 }
111 /* Pass function pointer in r7 */
112 init_reg_param(&args[n_args], "r7", 32, PARAM_OUT);
113 buf_set_u32(args[n_args].value, 0, 32, func_offset);
114 init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT);
115 buf_set_u32(args[n_args + 1].value, 0, 32, stacktop);
116
117
118 for (unsigned int i = 0; i < n_args + 2; ++i)
119 LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32));
120
121 /* Actually call the function */
122 alg_info.common_magic = ARMV7M_COMMON_MAGIC;
123 alg_info.core_mode = ARM_MODE_THREAD;
124 int err = target_run_algorithm(
125 target,
126 0, NULL, /* No memory arguments */
127 n_args + 1, args, /* User arguments + r7 */
128 priv->jump_debug_trampoline, priv->jump_debug_trampoline_end,
129 timeout_ms,
130 &alg_info
131 );
132 for (unsigned int i = 0; i < n_args + 2; ++i)
133 destroy_reg_param(&args[i]);
134 if (err != ERROR_OK)
135 LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset);
136 return err;
137
138 }
139
140 /* Finalize flash write/erase/read ID
141 * - flush cache
142 * - enters memory-mapped (XIP) mode to make flash data visible
143 * - deallocates target ROM func stack if previously allocated
144 */
145 static int rp2040_finalize_stack_free(struct flash_bank *bank)
146 {
147 struct rp2040_flash_bank *priv = bank->driver_priv;
148 struct target *target = bank->target;
149
150 /* Always flush before returning to execute-in-place, to invalidate stale
151 * cache contents. The flush call also restores regular hardware-controlled
152 * chip select following a rp2040_flash_exit_xip().
153 */
154 LOG_DEBUG("Flushing flash cache after write behind");
155 int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000);
156 if (err != ERROR_OK) {
157 LOG_ERROR("Failed to flush flash cache");
158 /* Intentionally continue after error and try to setup xip anyway */
159 }
160
161 LOG_DEBUG("Configuring SSI for execute-in-place");
162 err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000);
163 if (err != ERROR_OK)
164 LOG_ERROR("Failed to set SSI to XIP mode");
165
166 target_free_working_area(target, priv->stack);
167 priv->stack = NULL;
168 return err;
169 }
170
171 /* Prepare flash write/erase/read ID
172 * - allocates a stack for target ROM func
173 * - switches the SPI interface from memory-mapped mode to direct command mode
174 * Always pair with a call of rp2040_finalize_stack_free()
175 * after flash operation finishes or fails.
176 */
177 static int rp2040_stack_grab_and_prep(struct flash_bank *bank)
178 {
179 struct rp2040_flash_bank *priv = bank->driver_priv;
180 struct target *target = bank->target;
181
182 /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
183 const int STACK_SIZE = 256;
184 int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack);
185 if (err != ERROR_OK) {
186 LOG_ERROR("Could not allocate stack for flash programming code");
187 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
188 }
189
190 LOG_DEBUG("Connecting internal flash");
191 err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000);
192 if (err != ERROR_OK) {
193 LOG_ERROR("Failed to connect internal flash");
194 return err;
195 }
196
197 LOG_DEBUG("Kicking flash out of XIP mode");
198 err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000);
199 if (err != ERROR_OK) {
200 LOG_ERROR("Failed to exit flash XIP mode");
201 return err;
202 }
203
204 return ERROR_OK;
205 }
206
207 static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
208 {
209 LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset);
210
211 struct rp2040_flash_bank *priv = bank->driver_priv;
212 struct target *target = bank->target;
213
214 if (target->state != TARGET_HALTED) {
215 LOG_ERROR("Target not halted");
216 return ERROR_TARGET_NOT_HALTED;
217 }
218
219 struct working_area *bounce = NULL;
220
221 int err = rp2040_stack_grab_and_prep(bank);
222 if (err != ERROR_OK)
223 goto cleanup;
224
225 unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize;
226 /* We try to allocate working area rounded down to device page size,
227 * al least 1 page, at most the write data size
228 */
229 unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count);
230 err = target_alloc_working_area(target, chunk_size, &bounce);
231 if (err != ERROR_OK) {
232 LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
233 goto cleanup;
234 }
235
236 LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
237
238 while (count > 0) {
239 uint32_t write_size = count > chunk_size ? chunk_size : count;
240 LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset);
241 err = target_write_buffer(target, bounce->address, write_size, buffer);
242 if (err != ERROR_OK) {
243 LOG_ERROR("Could not load data into target bounce buffer");
244 break;
245 }
246 uint32_t args[3] = {
247 offset, /* addr */
248 bounce->address, /* data */
249 write_size /* count */
250 };
251 err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program,
252 args, ARRAY_SIZE(args), 3000);
253 if (err != ERROR_OK) {
254 LOG_ERROR("Failed to invoke flash programming code on target");
255 break;
256 }
257
258 buffer += write_size;
259 offset += write_size;
260 count -= write_size;
261 }
262
263 cleanup:
264 target_free_working_area(target, bounce);
265
266 rp2040_finalize_stack_free(bank);
267
268 return err;
269 }
270
271 static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
272 {
273 struct rp2040_flash_bank *priv = bank->driver_priv;
274 struct target *target = bank->target;
275
276 if (target->state != TARGET_HALTED) {
277 LOG_ERROR("Target not halted");
278 return ERROR_TARGET_NOT_HALTED;
279 }
280
281 uint32_t start_addr = bank->sectors[first].offset;
282 uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
283 LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
284
285 int err = rp2040_stack_grab_and_prep(bank);
286 if (err != ERROR_OK)
287 goto cleanup;
288
289 LOG_DEBUG("Remote call flash_range_erase");
290
291 uint32_t args[4] = {
292 bank->sectors[first].offset, /* addr */
293 bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */
294 priv->dev->sectorsize, /* block_size */
295 priv->dev->erase_cmd /* block_cmd */
296 };
297
298 /*
299 The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3:
300 https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
301 and the particular source code for said Boot ROM function can be found here:
302 https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
303
304 In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and
305 an optional larger "block" (size and command provided in args).
306 */
307
308 int timeout_ms = 2000 * (last - first) + 1000;
309 err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase,
310 args, ARRAY_SIZE(args), timeout_ms);
311
312 cleanup:
313 rp2040_finalize_stack_free(bank);
314
315 return err;
316 }
317
318 /* -----------------------------------------------------------------------------
319 Driver probing etc */
320
321 static int rp2040_ssel_active(struct target *target, bool active)
322 {
323 const target_addr_t qspi_ctrl_addr = 0x4001800c;
324 const uint32_t qspi_ctrl_outover_low = 2UL << 8;
325 const uint32_t qspi_ctrl_outover_high = 3UL << 8;
326 uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high;
327 uint32_t val;
328
329 int err = target_read_u32(target, qspi_ctrl_addr, &val);
330 if (err != ERROR_OK)
331 return err;
332
333 val = (val & ~qspi_ctrl_outover_high) | state;
334
335 err = target_write_u32(target, qspi_ctrl_addr, val);
336 if (err != ERROR_OK)
337 return err;
338
339 return ERROR_OK;
340 }
341
342 static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid)
343 {
344 uint32_t device_id = 0;
345 const target_addr_t ssi_dr0 = 0x18000060;
346
347 int err = rp2040_ssel_active(target, true);
348
349 /* write RDID request into SPI peripheral's FIFO */
350 for (int count = 0; (count < 4) && (err == ERROR_OK); count++)
351 err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID);
352
353 /* by this time, there is a receive FIFO entry for every write */
354 for (int count = 0; (count < 4) && (err == ERROR_OK); count++) {
355 uint32_t status;
356 err = target_read_u32(target, ssi_dr0, &status);
357
358 device_id >>= 8;
359 device_id |= (status & 0xFF) << 24;
360 }
361
362 if (err == ERROR_OK)
363 *devid = device_id >> 8;
364
365 int err2 = rp2040_ssel_active(target, false);
366 if (err2 != ERROR_OK)
367 LOG_ERROR("SSEL inactive failed");
368
369 return err;
370 }
371
372 static int rp2040_flash_probe(struct flash_bank *bank)
373 {
374 struct rp2040_flash_bank *priv = bank->driver_priv;
375 struct target *target = bank->target;
376
377 if (target->state != TARGET_HALTED) {
378 LOG_ERROR("Target not halted");
379 return ERROR_TARGET_NOT_HALTED;
380 }
381
382 int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline);
383 if (err != ERROR_OK) {
384 LOG_ERROR("Debug trampoline not found in RP2040 ROM.");
385 return err;
386 }
387 priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */
388
389 err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end);
390 if (err != ERROR_OK) {
391 LOG_ERROR("Debug trampoline end not found in RP2040 ROM.");
392 return err;
393 }
394 priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */
395
396 err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip);
397 if (err != ERROR_OK) {
398 LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM.");
399 return err;
400 }
401
402 err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash);
403 if (err != ERROR_OK) {
404 LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM.");
405 return err;
406 }
407
408 err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase);
409 if (err != ERROR_OK) {
410 LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM.");
411 return err;
412 }
413
414 err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program);
415 if (err != ERROR_OK) {
416 LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM.");
417 return err;
418 }
419
420 err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache);
421 if (err != ERROR_OK) {
422 LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM.");
423 return err;
424 }
425
426 err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip);
427 if (err != ERROR_OK) {
428 LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM.");
429 return err;
430 }
431
432 err = rp2040_stack_grab_and_prep(bank);
433
434 uint32_t device_id = 0;
435 if (err == ERROR_OK)
436 err = rp2040_spi_read_flash_id(target, &device_id);
437
438 rp2040_finalize_stack_free(bank);
439
440 if (err != ERROR_OK)
441 return err;
442
443 /* search for a SPI flash Device ID match */
444 priv->dev = NULL;
445 for (const struct flash_device *p = flash_devices; p->name ; p++)
446 if (p->device_id == device_id) {
447 priv->dev = p;
448 break;
449 }
450
451 if (!priv->dev) {
452 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id);
453 return ERROR_FAIL;
454 }
455
456 LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
457 priv->dev->name, priv->dev->device_id);
458
459 /* the Boot ROM flash_range_program() routine requires page alignment */
460 bank->write_start_alignment = priv->dev->pagesize;
461 bank->write_end_alignment = priv->dev->pagesize;
462
463 bank->size = priv->dev->size_in_bytes;
464
465 bank->num_sectors = bank->size / priv->dev->sectorsize;
466 LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n",
467 bank->size, bank->base, bank->num_sectors);
468 bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
469 if (!bank->sectors)
470 return ERROR_FAIL;
471
472 if (err == ERROR_OK)
473 priv->probed = true;
474
475 return err;
476 }
477
478 static int rp2040_flash_auto_probe(struct flash_bank *bank)
479 {
480 struct rp2040_flash_bank *priv = bank->driver_priv;
481
482 if (priv->probed)
483 return ERROR_OK;
484
485 return rp2040_flash_probe(bank);
486 }
487
488 static void rp2040_flash_free_driver_priv(struct flash_bank *bank)
489 {
490 free(bank->driver_priv);
491 bank->driver_priv = NULL;
492 }
493
494 /* -----------------------------------------------------------------------------
495 Driver boilerplate */
496
497 FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
498 {
499 struct rp2040_flash_bank *priv;
500 priv = malloc(sizeof(struct rp2040_flash_bank));
501 priv->probed = false;
502
503 /* Set up driver_priv */
504 bank->driver_priv = priv;
505
506 return ERROR_OK;
507 }
508
509 struct flash_driver rp2040_flash = {
510 .name = "rp2040_flash",
511 .flash_bank_command = rp2040_flash_bank_command,
512 .erase = rp2040_flash_erase,
513 .write = rp2040_flash_write,
514 .read = default_flash_read,
515 .probe = rp2040_flash_probe,
516 .auto_probe = rp2040_flash_auto_probe,
517 .erase_check = default_flash_blank_check,
518 .free_driver_priv = rp2040_flash_free_driver_priv
519 };

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)