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

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)