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

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)