flash/nor/rp2040: preparatory refactoring
[fw/openocd] / 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)
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                 3000, /* 3s timeout */
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 static int rp2040_stack_grab_and_prep(struct flash_bank *bank)
142 {
143         struct rp2040_flash_bank *priv = bank->driver_priv;
144         struct target *target = bank->target;
145
146         /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
147         const int STACK_SIZE = 256;
148         int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack);
149         if (err != ERROR_OK) {
150                 LOG_ERROR("Could not allocate stack for flash programming code");
151                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
152         }
153
154         LOG_DEBUG("Connecting internal flash");
155         err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0);
156         if (err != ERROR_OK) {
157                 LOG_ERROR("RP2040 erase: failed to connect internal flash");
158                 return err;
159         }
160
161         LOG_DEBUG("Kicking flash out of XIP mode");
162         err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0);
163         if (err != ERROR_OK) {
164                 LOG_ERROR("RP2040 erase: failed to exit flash XIP mode");
165                 return err;
166         }
167
168         return ERROR_OK;
169 }
170
171 static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
172 {
173         LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset);
174
175         struct rp2040_flash_bank *priv = bank->driver_priv;
176         struct target *target = bank->target;
177         struct working_area *bounce;
178
179         int err = rp2040_stack_grab_and_prep(bank);
180         if (err != ERROR_OK)
181                 return err;
182
183         const unsigned int chunk_size = target_get_working_area_avail(target);
184         if (target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) {
185                 LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
186                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
187         }
188
189         LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
190
191         while (count > 0) {
192                 uint32_t write_size = count > chunk_size ? chunk_size : count;
193                 LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset);
194                 err = target_write_buffer(target, bounce->address, write_size, buffer);
195                 if (err != ERROR_OK) {
196                         LOG_ERROR("Could not load data into target bounce buffer");
197                         break;
198                 }
199                 uint32_t args[3] = {
200                         offset, /* addr */
201                         bounce->address, /* data */
202                         write_size /* count */
203                 };
204                 err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args));
205                 if (err != ERROR_OK) {
206                         LOG_ERROR("Failed to invoke flash programming code on target");
207                         break;
208                 }
209
210                 buffer += write_size;
211                 offset += write_size;
212                 count -= write_size;
213         }
214         target_free_working_area(target, bounce);
215
216         if (err != ERROR_OK)
217                 return err;
218
219         /* Flash is successfully programmed. We can now do a bit of poking to make the flash
220            contents visible to us via memory-mapped (XIP) interface in the 0x1... memory region */
221         LOG_DEBUG("Flushing flash cache after write behind");
222         err = rp2040_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0);
223         if (err != ERROR_OK) {
224                 LOG_ERROR("RP2040 write: failed to flush flash cache");
225                 return err;
226         }
227         LOG_DEBUG("Configuring SSI for execute-in-place");
228         err = rp2040_call_rom_func(bank->target, priv, priv->jump_enter_cmd_xip, NULL, 0);
229         if (err != ERROR_OK)
230                 LOG_ERROR("RP2040 write: failed to flush flash cache");
231         return err;
232 }
233
234 static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
235 {
236         struct rp2040_flash_bank *priv = bank->driver_priv;
237         uint32_t start_addr = bank->sectors[first].offset;
238         uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
239         LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
240
241         int err = rp2040_stack_grab_and_prep(bank);
242         if (err != ERROR_OK)
243                 return err;
244
245         LOG_DEBUG("Remote call flash_range_erase");
246
247         uint32_t args[4] = {
248                 bank->sectors[first].offset, /* addr */
249                 bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */
250                 priv->dev->sectorsize, /* block_size */
251                 priv->dev->erase_cmd /* block_cmd */
252         };
253
254         /*
255         The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3:
256         https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
257         and the particular source code for said Boot ROM function can be found here:
258         https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
259
260         In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and
261         an optional larger "block" (size and command provided in args).  OpenOCD's spi.c only uses "block" sizes.
262         */
263
264         err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
265
266         return err;
267 }
268
269 /* -----------------------------------------------------------------------------
270    Driver probing etc */
271
272 static int rp2040_ssel_active(struct target *target, bool active)
273 {
274         const target_addr_t qspi_ctrl_addr = 0x4001800c;
275         const uint32_t qspi_ctrl_outover_low  = 2UL << 8;
276         const uint32_t qspi_ctrl_outover_high = 3UL << 8;
277         uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high;
278         uint32_t val;
279
280         int err = target_read_u32(target, qspi_ctrl_addr, &val);
281         if (err != ERROR_OK)
282                 return err;
283
284         val = (val & ~qspi_ctrl_outover_high) | state;
285
286         err = target_write_u32(target, qspi_ctrl_addr, val);
287         if (err != ERROR_OK)
288                 return err;
289
290         return ERROR_OK;
291 }
292
293 static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid)
294 {
295         uint32_t device_id = 0;
296         const target_addr_t ssi_dr0 = 0x18000060;
297
298         int err = rp2040_ssel_active(target, true);
299
300         /* write RDID request into SPI peripheral's FIFO */
301         for (int count = 0; (count < 4) && (err == ERROR_OK); count++)
302                 err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID);
303
304         /* by this time, there is a receive FIFO entry for every write */
305         for (int count = 0; (count < 4) && (err == ERROR_OK); count++) {
306                 uint32_t status;
307                 err = target_read_u32(target, ssi_dr0, &status);
308
309                 device_id >>= 8;
310                 device_id |= (status & 0xFF) << 24;
311         }
312
313         if (err == ERROR_OK)
314                 *devid = device_id >> 8;
315
316         int err2 = rp2040_ssel_active(target, false);
317         if (err2 != ERROR_OK)
318                 LOG_ERROR("SSEL inactive failed");
319
320         return err;
321 }
322
323 static int rp2040_flash_probe(struct flash_bank *bank)
324 {
325         struct rp2040_flash_bank *priv = bank->driver_priv;
326         struct target *target = bank->target;
327
328         int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline);
329         if (err != ERROR_OK) {
330                 LOG_ERROR("Debug trampoline not found in RP2040 ROM.");
331                 return err;
332         }
333         priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */
334
335         err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end);
336         if (err != ERROR_OK) {
337                 LOG_ERROR("Debug trampoline end not found in RP2040 ROM.");
338                 return err;
339         }
340         priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */
341
342         err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip);
343         if (err != ERROR_OK) {
344                 LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM.");
345                 return err;
346         }
347
348         err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash);
349         if (err != ERROR_OK) {
350                 LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM.");
351                 return err;
352         }
353
354         err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase);
355         if (err != ERROR_OK) {
356                 LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM.");
357                 return err;
358         }
359
360         err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program);
361         if (err != ERROR_OK) {
362                 LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM.");
363                 return err;
364         }
365
366         err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache);
367         if (err != ERROR_OK) {
368                 LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM.");
369                 return err;
370         }
371
372         err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip);
373         if (err != ERROR_OK) {
374                 LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM.");
375                 return err;
376         }
377
378         err = rp2040_stack_grab_and_prep(bank);
379         if (err != ERROR_OK)
380                 return err;
381
382         uint32_t device_id = 0;
383         err = rp2040_spi_read_flash_id(target, &device_id);
384         if (err != ERROR_OK)
385                 return err;
386
387         /* search for a SPI flash Device ID match */
388         priv->dev = NULL;
389         for (const struct flash_device *p = flash_devices; p->name ; p++)
390                 if (p->device_id == device_id) {
391                         priv->dev = p;
392                         break;
393                 }
394
395         if (!priv->dev) {
396                 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id);
397                 return ERROR_FAIL;
398         }
399
400         LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
401                 priv->dev->name, priv->dev->device_id);
402
403         /* the Boot ROM flash_range_program() routine requires page alignment */
404         bank->write_start_alignment = priv->dev->pagesize;
405         bank->write_end_alignment = priv->dev->pagesize;
406
407         bank->size = priv->dev->size_in_bytes;
408
409         bank->num_sectors = bank->size / priv->dev->sectorsize;
410         LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n",
411                 bank->size, bank->base, bank->num_sectors);
412         bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
413         if (!bank->sectors)
414                 return ERROR_FAIL;
415
416         if (err == ERROR_OK)
417                 priv->probed = true;
418
419         return err;
420 }
421
422 static int rp2040_flash_auto_probe(struct flash_bank *bank)
423 {
424         struct rp2040_flash_bank *priv = bank->driver_priv;
425
426         if (priv->probed)
427                 return ERROR_OK;
428
429         return rp2040_flash_probe(bank);
430 }
431
432 static void rp2040_flash_free_driver_priv(struct flash_bank *bank)
433 {
434         free(bank->driver_priv);
435         bank->driver_priv = NULL;
436 }
437
438 /* -----------------------------------------------------------------------------
439    Driver boilerplate */
440
441 FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
442 {
443         struct rp2040_flash_bank *priv;
444         priv = malloc(sizeof(struct rp2040_flash_bank));
445         priv->probed = false;
446
447         /* Set up driver_priv */
448         bank->driver_priv = priv;
449
450         return ERROR_OK;
451 }
452
453 struct flash_driver rp2040_flash = {
454         .name = "rp2040_flash",
455         .flash_bank_command = rp2040_flash_bank_command,
456         .erase =  rp2040_flash_erase,
457         .write = rp2040_flash_write,
458         .read = default_flash_read,
459         .probe = rp2040_flash_probe,
460         .auto_probe = rp2040_flash_auto_probe,
461         .erase_check = default_flash_blank_check,
462         .free_driver_priv = rp2040_flash_free_driver_priv
463 };