1 // SPDX-License-Identifier: GPL-2.0-or-later
8 #include <helper/binarybuffer.h>
9 #include <target/algorithm.h>
10 #include <target/armv7m.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 */
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
)
56 int err
= target_read_u32(target
, BOOTROM_MAGIC_ADDR
, &magic
);
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");
65 LOG_ERROR("RP2040 BOOT ROM not found");
69 /* dereference the table pointer */
71 err
= target_read_u16(target
, BOOTROM_MAGIC_ADDR
+ 4, &table_entry
);
77 err
= target_read_u16(target
, table_entry
, &entry_tag
);
80 if (entry_tag
== tag
) {
81 /* 16 bit symbol is next */
82 return target_read_u16(target
, table_entry
+ 2, symbol
);
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
)
92 char *regnames
[4] = { "r0", "r1", "r2", "r3" };
94 assert(n_args
<= ARRAY_SIZE(regnames
)); /* only allow register arguments */
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_TARGET_DEBUG(target
, "Calling ROM func @0x%" PRIx16
" with %u arguments", func_offset
, n_args
);
104 struct reg_param args
[ARRAY_SIZE(regnames
) + 2];
105 struct armv7m_algorithm alg_info
;
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
]);
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
);
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 */
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));
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(
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
,
134 for (unsigned int i
= 0; i
< n_reg_params
; ++i
)
135 destroy_reg_param(&args
[i
]);
138 LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16
, func_offset
);
143 /* Finalize flash write/erase/read ID
145 * - enters memory-mapped (XIP) mode to make flash data visible
146 * - deallocates target ROM func stack if previously allocated
148 static int rp2040_finalize_stack_free(struct flash_bank
*bank
)
150 struct rp2040_flash_bank
*priv
= bank
->driver_priv
;
151 struct target
*target
= bank
->target
;
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().
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 */
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);
167 LOG_ERROR("Failed to set SSI to XIP mode");
169 target_free_working_area(target
, priv
->stack
);
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.
180 static int rp2040_stack_grab_and_prep(struct flash_bank
*bank
)
182 struct rp2040_flash_bank
*priv
= bank
->driver_priv
;
183 struct target
*target
= bank
->target
;
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
;
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");
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");
210 static int rp2040_flash_write(struct flash_bank
*bank
, const uint8_t *buffer
, uint32_t offset
, uint32_t count
)
212 LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32
, count
, offset
);
214 struct rp2040_flash_bank
*priv
= bank
->driver_priv
;
215 struct target
*target
= bank
->target
;
217 if (target
->state
!= TARGET_HALTED
) {
218 LOG_ERROR("Target not halted");
219 return ERROR_TARGET_NOT_HALTED
;
222 struct working_area
*bounce
= NULL
;
224 int err
= rp2040_stack_grab_and_prep(bank
);
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
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");
239 LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT
, bounce
->address
);
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");
251 bounce
->address
, /* data */
252 write_size
/* count */
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");
261 buffer
+= write_size
;
262 offset
+= write_size
;
267 target_free_working_area(target
, bounce
);
269 rp2040_finalize_stack_free(bank
);
274 static int rp2040_flash_erase(struct flash_bank
*bank
, unsigned int first
, unsigned int last
)
276 struct rp2040_flash_bank
*priv
= bank
->driver_priv
;
277 struct target
*target
= bank
->target
;
279 if (target
->state
!= TARGET_HALTED
) {
280 LOG_ERROR("Target not halted");
281 return ERROR_TARGET_NOT_HALTED
;
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
);
288 int err
= rp2040_stack_grab_and_prep(bank
);
292 LOG_DEBUG("Remote call flash_range_erase");
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 */
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
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).
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
);
316 rp2040_finalize_stack_free(bank
);
321 /* -----------------------------------------------------------------------------
322 Driver probing etc */
324 static int rp2040_ssel_active(struct target
*target
, bool active
)
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
;
332 int err
= target_read_u32(target
, qspi_ctrl_addr
, &val
);
336 val
= (val
& ~qspi_ctrl_outover_high
) | state
;
338 err
= target_write_u32(target
, qspi_ctrl_addr
, val
);
345 static int rp2040_spi_read_flash_id(struct target
*target
, uint32_t *devid
)
347 uint32_t device_id
= 0;
348 const target_addr_t ssi_dr0
= 0x18000060;
350 int err
= rp2040_ssel_active(target
, true);
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
);
356 /* by this time, there is a receive FIFO entry for every write */
357 for (int count
= 0; (count
< 4) && (err
== ERROR_OK
); count
++) {
359 err
= target_read_u32(target
, ssi_dr0
, &status
);
362 device_id
|= (status
& 0xFF) << 24;
366 *devid
= device_id
>> 8;
368 int err2
= rp2040_ssel_active(target
, false);
369 if (err2
!= ERROR_OK
)
370 LOG_ERROR("SSEL inactive failed");
375 static int rp2040_flash_probe(struct flash_bank
*bank
)
377 struct rp2040_flash_bank
*priv
= bank
->driver_priv
;
378 struct target
*target
= bank
->target
;
380 if (target
->state
!= TARGET_HALTED
) {
381 LOG_ERROR("Target not halted");
382 return ERROR_TARGET_NOT_HALTED
;
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.");
390 priv
->jump_debug_trampoline
&= ~1u; /* mask off thumb bit */
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.");
397 priv
->jump_debug_trampoline_end
&= ~1u; /* mask off thumb bit */
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.");
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.");
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.");
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.");
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.");
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.");
435 err
= rp2040_stack_grab_and_prep(bank
);
437 uint32_t device_id
= 0;
439 err
= rp2040_spi_read_flash_id(target
, &device_id
);
441 rp2040_finalize_stack_free(bank
);
446 /* search for a SPI flash Device ID match */
448 for (const struct flash_device
*p
= flash_devices
; p
->name
; p
++)
449 if (p
->device_id
== device_id
) {
455 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32
")", device_id
);
459 LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32
")",
460 priv
->dev
->name
, priv
->dev
->device_id
);
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
;
466 bank
->size
= priv
->dev
->size_in_bytes
;
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
);
481 static int rp2040_flash_auto_probe(struct flash_bank
*bank
)
483 struct rp2040_flash_bank
*priv
= bank
->driver_priv
;
488 return rp2040_flash_probe(bank
);
491 static void rp2040_flash_free_driver_priv(struct flash_bank
*bank
)
493 free(bank
->driver_priv
);
494 bank
->driver_priv
= NULL
;
497 /* -----------------------------------------------------------------------------
498 Driver boilerplate */
500 FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command
)
502 struct rp2040_flash_bank
*priv
;
503 priv
= malloc(sizeof(struct rp2040_flash_bank
));
504 priv
->probed
= false;
506 /* Set up driver_priv */
507 bank
->driver_priv
= priv
;
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
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)