flash/nor/fespi: check target type
[openocd.git] / src / flash / nor / psoc6.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4 * *
5 * Copyright (C) 2018 by Bohdan Tymkiv *
6 * bohdan.tymkiv@cypress.com bohdan200@gmail.com *
7 ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include <time.h>
14
15 #include "imp.h"
16 #include "helper/time_support.h"
17 #include "target/arm_adi_v5.h"
18 #include "target/target.h"
19 #include "target/cortex_m.h"
20 #include "target/breakpoints.h"
21 #include "target/target_type.h"
22 #include "target/algorithm.h"
23
24 /**************************************************************************************************
25 * PSoC6 device definitions
26 *************************************************************************************************/
27 #define MFLASH_SECTOR_SIZE (256u * 1024u)
28 #define WFLASH_SECTOR_SIZE (32u * 1024u)
29
30 #define MEM_BASE_MFLASH 0x10000000u
31 #define MEM_BASE_WFLASH 0x14000000u
32 #define MEM_WFLASH_SIZE 32768u
33 #define MEM_BASE_SFLASH 0x16000000u
34 #define RAM_STACK_WA_SIZE 2048u
35 #define PSOC6_SPCIF_GEOMETRY 0x4025F00Cu
36
37 #define PROTECTION_UNKNOWN 0x00u
38 #define PROTECTION_VIRGIN 0x01u
39 #define PROTECTION_NORMAL 0x02u
40 #define PROTECTION_SECURE 0x03u
41 #define PROTECTION_DEAD 0x04u
42
43 #define MEM_BASE_IPC 0x40230000u
44 #define IPC_STRUCT_SIZE 0x20u
45 #define MEM_IPC(n) (MEM_BASE_IPC + (n) * IPC_STRUCT_SIZE)
46 #define MEM_IPC_ACQUIRE(n) (MEM_IPC(n) + 0x00u)
47 #define MEM_IPC_NOTIFY(n) (MEM_IPC(n) + 0x08u)
48 #define MEM_IPC_DATA(n) (MEM_IPC(n) + 0x0Cu)
49 #define MEM_IPC_LOCK_STATUS(n) (MEM_IPC(n) + 0x10u)
50
51 #define MEM_BASE_IPC_INTR 0x40231000u
52 #define IPC_INTR_STRUCT_SIZE 0x20u
53 #define MEM_IPC_INTR(n) (MEM_BASE_IPC_INTR + (n) * IPC_INTR_STRUCT_SIZE)
54 #define MEM_IPC_INTR_MASK(n) (MEM_IPC_INTR(n) + 0x08u)
55 #define IPC_ACQUIRE_SUCCESS_MSK 0x80000000u
56 #define IPC_LOCK_ACQUIRED_MSK 0x80000000u
57
58 #define IPC_ID 2u
59 #define IPC_INTR_ID 0u
60 #define IPC_TIMEOUT_MS 1000
61
62 #define SROMAPI_SIID_REQ 0x00000001u
63 #define SROMAPI_SIID_REQ_FAMILY_REVISION (SROMAPI_SIID_REQ | 0x000u)
64 #define SROMAPI_SIID_REQ_SIID_PROTECTION (SROMAPI_SIID_REQ | 0x100u)
65 #define SROMAPI_WRITEROW_REQ 0x05000100u
66 #define SROMAPI_PROGRAMROW_REQ 0x06000100u
67 #define SROMAPI_ERASESECTOR_REQ 0x14000100u
68 #define SROMAPI_ERASEALL_REQ 0x0A000100u
69 #define SROMAPI_ERASEROW_REQ 0x1C000100u
70
71 #define SROMAPI_STATUS_MSK 0xF0000000u
72 #define SROMAPI_STAT_SUCCESS 0xA0000000u
73 #define SROMAPI_DATA_LOCATION_MSK 0x00000001u
74 #define SROMAPI_CALL_TIMEOUT_MS 1500
75
76 struct psoc6_target_info {
77 uint32_t silicon_id;
78 uint8_t protection;
79 uint32_t main_flash_sz;
80 uint32_t row_sz;
81 bool is_probed;
82 };
83
84 struct timeout {
85 int64_t start_time;
86 long timeout_ms;
87 };
88
89 struct row_region {
90 uint32_t addr;
91 size_t size;
92 };
93
94 static const struct row_region safe_sflash_regions[] = {
95 {0x16000800, 0x800}, /* SFLASH: User Data */
96 {0x16001A00, 0x200}, /* SFLASH: NAR */
97 {0x16005A00, 0xC00}, /* SFLASH: Public Key */
98 {0x16007C00, 0x400}, /* SFLASH: TOC2 */
99 };
100
101 #define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
102
103 static struct working_area *g_stack_area;
104 static struct armv7m_algorithm g_armv7m_info;
105
106 /** ***********************************************************************************************
107 * @brief Initializes `struct timeout` structure with given timeout value
108 * @param to pointer to `struct timeout` structure
109 * @param timeout_ms timeout, in milliseconds
110 *************************************************************************************************/
111 static void timeout_init(struct timeout *to, long timeout_ms)
112 {
113 to->start_time = timeval_ms();
114 to->timeout_ms = timeout_ms;
115 }
116
117 /** ***********************************************************************************************
118 * @brief Returns true if given `struct timeout` structure has expired
119 * @param to pointer to `struct timeout` structure
120 * @return true if timeout expired
121 *************************************************************************************************/
122 static bool timeout_expired(struct timeout *to)
123 {
124 return (timeval_ms() - to->start_time) > to->timeout_ms;
125 }
126
127 /** ***********************************************************************************************
128 * @brief Starts pseudo flash algorithm and leaves it running. Function allocates working area for
129 * algorithm code and CPU stack, adjusts stack pointer, uploads and starts the algorithm.
130 * Algorithm (a basic infinite loop) runs asynchronously while driver performs Flash operations.
131 *
132 * @param target target for the algorithm
133 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
134 *************************************************************************************************/
135 static int sromalgo_prepare(struct target *target)
136 {
137 int hr;
138
139 /* Initialize Vector Table Offset register (in case FW modified it) */
140 hr = target_write_u32(target, 0xE000ED08, 0x00000000);
141 if (hr != ERROR_OK)
142 return hr;
143
144 /* Allocate Working Area for Stack and Flash algorithm */
145 hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
146 if (hr != ERROR_OK)
147 return hr;
148
149 g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
150 g_armv7m_info.core_mode = ARM_MODE_THREAD;
151
152 struct reg_param reg_params;
153 init_reg_param(&reg_params, "sp", 32, PARAM_OUT);
154 buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size);
155
156 /* Write basic infinite loop algorithm to target RAM */
157 hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7);
158 if (hr != ERROR_OK)
159 goto destroy_rp_free_wa;
160
161 hr = target_start_algorithm(target, 0, NULL, 1, &reg_params, g_stack_area->address,
162 0, &g_armv7m_info);
163 if (hr != ERROR_OK)
164 goto destroy_rp_free_wa;
165
166 destroy_reg_param(&reg_params);
167
168 return hr;
169
170 destroy_rp_free_wa:
171 /* Something went wrong, do some cleanup */
172 destroy_reg_param(&reg_params);
173
174 target_free_working_area(target, g_stack_area);
175 g_stack_area = NULL;
176
177 return hr;
178 }
179
180 /** ***********************************************************************************************
181 * @brief Stops running flash algorithm and releases associated resources.
182 * This function is also used for cleanup in case of errors so g_stack_area may be NULL.
183 * These cases have to be handled gracefully.
184 *
185 * @param target current target
186 *************************************************************************************************/
187 static void sromalgo_release(struct target *target)
188 {
189 int hr = ERROR_OK;
190
191 if (g_stack_area) {
192 /* Stop flash algorithm if it is running */
193 if (target->running_alg) {
194 hr = target_halt(target);
195 if (hr != ERROR_OK)
196 goto exit_free_wa;
197
198 hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
199 IPC_TIMEOUT_MS, &g_armv7m_info);
200 if (hr != ERROR_OK)
201 goto exit_free_wa;
202 }
203
204 exit_free_wa:
205 /* Free Stack/Flash algorithm working area */
206 target_free_working_area(target, g_stack_area);
207 g_stack_area = NULL;
208 }
209 }
210
211 /** ***********************************************************************************************
212 * @brief Waits for expected IPC lock status. PSoC6 uses IPC structures for inter-core
213 * communication. Same IPCs are used to invoke SROM API. IPC structure must be locked prior to
214 * invoking any SROM API. This ensures nothing else in the system will use same IPC thus corrupting
215 * our data. Locking is performed by ipc_acquire(), this function ensures that IPC is actually
216 * in expected state
217 *
218 * @param target current target
219 * @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access
220 * @param lock_expected expected lock status
221 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
222 *************************************************************************************************/
223 static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected)
224 {
225 int hr;
226 uint32_t reg_val;
227
228 struct timeout to;
229 timeout_init(&to, IPC_TIMEOUT_MS);
230
231 while (!timeout_expired(&to)) {
232 /* Process any server requests */
233 keep_alive();
234
235 /* Read IPC Lock status */
236 hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), &reg_val);
237 if (hr != ERROR_OK) {
238 LOG_ERROR("Unable to read IPC Lock Status register");
239 return hr;
240 }
241
242 bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
243
244 if (lock_expected == is_locked)
245 return ERROR_OK;
246 }
247
248 if (target->coreid) {
249 LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. "
250 "Please perform all Flash-related operations via CM0+ target on dual-core devices.");
251 }
252
253 LOG_ERROR("Timeout polling IPC Lock Status");
254 return ERROR_TARGET_TIMEOUT;
255 }
256
257 /** ***********************************************************************************************
258 * @brief Acquires IPC structure. PSoC6 uses IPC structures for inter-core communication.
259 * Same IPCs are used to invoke SROM API. IPC structure must be locked prior to invoking any SROM API.
260 * This ensures nothing else in the system will use same IPC thus corrupting our data.
261 * This function locks the IPC.
262 *
263 * @param target current target
264 * @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP access
265 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
266 *************************************************************************************************/
267 static int ipc_acquire(struct target *target, char ipc_id)
268 {
269 int hr = ERROR_OK;
270 bool is_acquired = false;
271 uint32_t reg_val;
272
273 struct timeout to;
274 timeout_init(&to, IPC_TIMEOUT_MS);
275
276 while (!timeout_expired(&to)) {
277 keep_alive();
278
279 hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), IPC_ACQUIRE_SUCCESS_MSK);
280 if (hr != ERROR_OK) {
281 LOG_ERROR("Unable to write to IPC Acquire register");
282 return hr;
283 }
284
285 /* Check if data is written on first step */
286 hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), &reg_val);
287 if (hr != ERROR_OK) {
288 LOG_ERROR("Unable to read IPC Acquire register");
289 return hr;
290 }
291
292 is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
293 if (is_acquired) {
294 /* If IPC structure is acquired, the lock status should be set */
295 hr = ipc_poll_lock_stat(target, ipc_id, true);
296 break;
297 }
298 }
299
300 if (!is_acquired)
301 LOG_ERROR("Timeout acquiring IPC structure");
302
303 return hr;
304 }
305
306 /** ***********************************************************************************************
307 * @brief Invokes SROM API functions which are responsible for Flash operations
308 *
309 * @param target current target
310 * @param req_and_params request id of the function to invoke
311 * @param working_area address of memory buffer in target's memory space for SROM API parameters
312 * @param data_out pointer to variable which will be populated with execution status
313 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
314 *************************************************************************************************/
315 static int call_sromapi(struct target *target,
316 uint32_t req_and_params,
317 uint32_t working_area,
318 uint32_t *data_out)
319 {
320 int hr;
321
322 bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
323
324 hr = ipc_acquire(target, IPC_ID);
325 if (hr != ERROR_OK)
326 return hr;
327
328 if (is_data_in_ram)
329 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area);
330 else
331 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params);
332
333 if (hr != ERROR_OK)
334 return hr;
335
336 /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */
337 hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + IPC_ID));
338 if (hr != ERROR_OK)
339 return hr;
340
341 hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
342 if (hr != ERROR_OK)
343 return hr;
344
345 /* Poll lock status */
346 hr = ipc_poll_lock_stat(target, IPC_ID, false);
347 if (hr != ERROR_OK)
348 return hr;
349
350 /* Poll Data byte */
351 if (is_data_in_ram)
352 hr = target_read_u32(target, working_area, data_out);
353 else
354 hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out);
355
356 if (hr != ERROR_OK) {
357 LOG_ERROR("Error reading SROM API Status location");
358 return hr;
359 }
360
361 bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS;
362 if (!is_success) {
363 LOG_ERROR("SROM API execution failed. Status: 0x%08" PRIX32, *data_out);
364 return ERROR_TARGET_FAILURE;
365 }
366
367 return ERROR_OK;
368 }
369
370 /** ***********************************************************************************************
371 * @brief Retrieves SiliconID and Protection status of the target device
372 * @param target current target
373 * @param si_id pointer to variable, will be populated with SiliconID
374 * @param protection pointer to variable, will be populated with protection status
375 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
376 *************************************************************************************************/
377 static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection)
378 {
379 int hr;
380 uint32_t family_rev, siid_prot;
381
382 hr = sromalgo_prepare(target);
383 if (hr != ERROR_OK)
384 goto exit;
385
386 /* Read FamilyID and Revision */
387 hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev);
388 if (hr != ERROR_OK)
389 goto exit;
390
391 /* Read SiliconID and Protection */
392 hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
393 if (hr != ERROR_OK)
394 goto exit;
395
396 *si_id = (siid_prot & 0x0000FFFF) << 16;
397 *si_id |= (family_rev & 0x00FF0000) >> 8;
398 *si_id |= (family_rev & 0x000000FF) >> 0;
399
400 *protection = (siid_prot & 0x000F0000) >> 0x10;
401
402 exit:
403 sromalgo_release(target);
404 return ERROR_OK;
405 }
406
407 /** ***********************************************************************************************
408 * @brief Translates Protection status to openocd-friendly boolean value
409 * @param bank current flash bank
410 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
411 *************************************************************************************************/
412 static int psoc6_protect_check(struct flash_bank *bank)
413 {
414 int is_protected;
415
416 struct psoc6_target_info *psoc6_info = bank->driver_priv;
417 int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
418 if (hr != ERROR_OK)
419 return hr;
420
421 switch (psoc6_info->protection) {
422 case PROTECTION_VIRGIN:
423 case PROTECTION_NORMAL:
424 is_protected = 0;
425 break;
426
427 case PROTECTION_UNKNOWN:
428 case PROTECTION_SECURE:
429 case PROTECTION_DEAD:
430 default:
431 is_protected = 1;
432 break;
433 }
434
435 for (unsigned int i = 0; i < bank->num_sectors; i++)
436 bank->sectors[i].is_protected = is_protected;
437
438 return ERROR_OK;
439 }
440
441 /** ***********************************************************************************************
442 * @brief Dummy function, Life Cycle transition is not currently supported
443 * @return ERROR_OK always
444 *************************************************************************************************/
445 static int psoc6_protect(struct flash_bank *bank, int set, unsigned int first,
446 unsigned int last)
447 {
448 (void)bank;
449 (void)set;
450 (void)first;
451 (void)last;
452
453 LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
454 return ERROR_OK;
455 }
456
457 /** ***********************************************************************************************
458 * @brief Translates Protection status to string
459 * @param protection protection value
460 * @return pointer to const string describing protection status
461 *************************************************************************************************/
462 static const char *protection_to_str(uint8_t protection)
463 {
464 switch (protection) {
465 case PROTECTION_VIRGIN:
466 return "VIRGIN";
467 case PROTECTION_NORMAL:
468 return "NORMAL";
469 case PROTECTION_SECURE:
470 return "SECURE";
471 case PROTECTION_DEAD:
472 return "DEAD";
473 case PROTECTION_UNKNOWN:
474 default:
475 return "UNKNOWN";
476 }
477 }
478
479 /** ***********************************************************************************************
480 * @brief psoc6_get_info Displays human-readable information about acquired device
481 * @param bank current flash bank
482 * @param cmd pointer to command invocation instance
483 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
484 *************************************************************************************************/
485 static int psoc6_get_info(struct flash_bank *bank, struct command_invocation *cmd)
486 {
487 struct psoc6_target_info *psoc6_info = bank->driver_priv;
488
489 if (psoc6_info->is_probed == false)
490 return ERROR_FAIL;
491
492 int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
493 if (hr != ERROR_OK)
494 return hr;
495
496 command_print_sameline(cmd,
497 "PSoC6 Silicon ID: 0x%08" PRIX32 "\n"
498 "Protection: %s\n"
499 "Main Flash size: %" PRIu32 " kB\n"
500 "Work Flash size: 32 kB\n",
501 psoc6_info->silicon_id,
502 protection_to_str(psoc6_info->protection),
503 psoc6_info->main_flash_sz / 1024);
504
505 return ERROR_OK;
506 }
507
508 /** ***********************************************************************************************
509 * @brief Checks if given flash bank belongs to Supervisory Flash
510 * @param bank current flash bank
511 * @return true if flash bank belongs to Supervisory Flash
512 *************************************************************************************************/
513 static bool is_sflash_bank(struct flash_bank *bank)
514 {
515 for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
516 if (bank->base == safe_sflash_regions[i].addr)
517 return true;
518 }
519
520 return false;
521 }
522
523 /** ***********************************************************************************************
524 * @brief Checks if given flash bank belongs to Work Flash
525 * @param bank current flash bank
526 * @return true if flash bank belongs to Work Flash
527 *************************************************************************************************/
528 static inline bool is_wflash_bank(struct flash_bank *bank)
529 {
530 return (bank->base == MEM_BASE_WFLASH);
531 }
532
533 /** ***********************************************************************************************
534 * @brief Checks if given flash bank belongs to Main Flash
535 * @param bank current flash bank
536 * @return true if flash bank belongs to Main Flash
537 *************************************************************************************************/
538 static inline bool is_mflash_bank(struct flash_bank *bank)
539 {
540 return (bank->base == MEM_BASE_MFLASH);
541 }
542
543 /** ***********************************************************************************************
544 * @brief Probes the device and populates related data structures with target flash geometry data.
545 * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a
546 * running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers)
547 *
548 * @param bank current flash bank
549 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
550 *************************************************************************************************/
551 static int psoc6_probe(struct flash_bank *bank)
552 {
553 struct target *target = bank->target;
554 struct psoc6_target_info *psoc6_info = bank->driver_priv;
555
556 int hr = ERROR_OK;
557
558 /* Retrieve data from SPCIF_GEOMETRY */
559 uint32_t geom;
560 target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom);
561 uint32_t row_sz_lg2 = (geom & 0xF0) >> 4;
562 uint32_t row_sz = (0x01 << row_sz_lg2);
563 uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8);
564 uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24);
565
566 /* Calculate size of Main Flash*/
567 uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz;
568
569 free(bank->sectors);
570 bank->sectors = NULL;
571
572 size_t bank_size = 0;
573
574 if (is_mflash_bank(bank))
575 bank_size = flash_sz_bytes;
576 else if (is_wflash_bank(bank))
577 bank_size = MEM_WFLASH_SIZE;
578 else if (is_sflash_bank(bank)) {
579 for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
580 if (safe_sflash_regions[i].addr == bank->base) {
581 bank_size = safe_sflash_regions[i].size;
582 break;
583 }
584 }
585 }
586
587 if (bank_size == 0) {
588 LOG_ERROR("Invalid Flash Bank base address in config file");
589 return ERROR_FLASH_BANK_INVALID;
590 }
591
592 unsigned int num_sectors = bank_size / row_sz;
593 bank->size = bank_size;
594 bank->chip_width = 4;
595 bank->bus_width = 4;
596 bank->erased_value = 0;
597 bank->default_padded_value = 0;
598
599 bank->num_sectors = num_sectors;
600 bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
601 for (unsigned int i = 0; i < num_sectors; i++) {
602 bank->sectors[i].size = row_sz;
603 bank->sectors[i].offset = i * row_sz;
604 bank->sectors[i].is_erased = -1;
605 bank->sectors[i].is_protected = -1;
606 }
607
608 psoc6_info->is_probed = true;
609 psoc6_info->main_flash_sz = flash_sz_bytes;
610 psoc6_info->row_sz = row_sz;
611
612 return hr;
613 }
614
615 /** ***********************************************************************************************
616 * @brief Probes target device only if it hasn't been probed yet
617 * @param bank current flash bank
618 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
619 *************************************************************************************************/
620 static int psoc6_auto_probe(struct flash_bank *bank)
621 {
622 struct psoc6_target_info *psoc6_info = bank->driver_priv;
623 int hr;
624
625 if (psoc6_info->is_probed)
626 hr = ERROR_OK;
627 else
628 hr = psoc6_probe(bank);
629
630 return hr;
631 }
632
633 /** ***********************************************************************************************
634 * @brief Erases single sector (256k) on target device
635 * @param bank current flash bank
636 * @param wa working area for SROM API parameters
637 * @param addr starting address of the sector
638 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
639 *************************************************************************************************/
640 static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
641 {
642 struct target *target = bank->target;
643
644 LOG_DEBUG("Erasing SECTOR @%08" PRIX32, addr);
645
646 int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ);
647 if (hr != ERROR_OK)
648 return hr;
649
650 hr = target_write_u32(target, wa->address + 0x04, addr);
651 if (hr != ERROR_OK)
652 return hr;
653
654 uint32_t data_out;
655 hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out);
656 if (hr != ERROR_OK)
657 LOG_ERROR("SECTOR @%08" PRIX32 " not erased!", addr);
658
659 return hr;
660 }
661
662 /** ***********************************************************************************************
663 * @brief Erases single row (512b) on target device
664 * @param bank current flash bank
665 * @param wa working area for SROM API parameters
666 * @param addr starting address of the flash row
667 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
668 *************************************************************************************************/
669 static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
670 {
671 struct target *target = bank->target;
672
673 LOG_DEBUG("Erasing ROW @%08" PRIX32, addr);
674
675 int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ);
676 if (hr != ERROR_OK)
677 return hr;
678
679 hr = target_write_u32(target, wa->address + 0x04, addr);
680 if (hr != ERROR_OK)
681 return hr;
682
683 uint32_t data_out;
684 hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out);
685 if (hr != ERROR_OK)
686 LOG_ERROR("ROW @%08" PRIX32 " not erased!", addr);
687
688 return hr;
689 }
690
691 /** ***********************************************************************************************
692 * @brief Performs Erase operation. Function will try to use biggest erase block possible to
693 * speedup the operation.
694 *
695 * @param bank current flash bank
696 * @param first first sector to erase
697 * @param last last sector to erase
698 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
699 *************************************************************************************************/
700 static int psoc6_erase(struct flash_bank *bank, unsigned int first,
701 unsigned int last)
702 {
703 struct target *target = bank->target;
704 struct psoc6_target_info *psoc6_info = bank->driver_priv;
705 const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE : MFLASH_SECTOR_SIZE;
706
707 int hr;
708 struct working_area *wa;
709
710 if (is_sflash_bank(bank)) {
711 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
712 return ERROR_OK;
713 }
714
715 hr = sromalgo_prepare(target);
716 if (hr != ERROR_OK)
717 goto exit;
718
719 hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
720 if (hr != ERROR_OK)
721 goto exit;
722
723 /* Number of rows in single sector */
724 const unsigned int rows_in_sector = sector_size / psoc6_info->row_sz;
725
726 while (last >= first) {
727 /* Erase Sector if we are on sector boundary and erase size covers whole sector */
728 if ((first % rows_in_sector) == 0 &&
729 (last - first + 1) >= rows_in_sector) {
730 hr = psoc6_erase_sector(bank, wa, bank->base + first * psoc6_info->row_sz);
731 if (hr != ERROR_OK)
732 goto exit_free_wa;
733
734 first += rows_in_sector;
735 } else {
736 /* Perform Row Erase otherwise */
737 hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz);
738 if (hr != ERROR_OK)
739 goto exit_free_wa;
740
741 first += 1;
742 }
743 }
744
745 exit_free_wa:
746 target_free_working_area(target, wa);
747 exit:
748 sromalgo_release(target);
749 return hr;
750 }
751
752 /** ***********************************************************************************************
753 * @brief Programs single Flash Row
754 * @param bank current flash bank
755 * @param addr address of the flash row
756 * @param buffer pointer to the buffer with data
757 * @param is_sflash true if current flash bank belongs to Supervisory Flash
758 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
759 *************************************************************************************************/
760 static int psoc6_program_row(struct flash_bank *bank,
761 uint32_t addr,
762 const uint8_t *buffer,
763 bool is_sflash)
764 {
765 struct target *target = bank->target;
766 struct psoc6_target_info *psoc6_info = bank->driver_priv;
767 struct working_area *wa;
768 const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : SROMAPI_PROGRAMROW_REQ;
769 uint32_t data_out;
770 int hr = ERROR_OK;
771
772 LOG_DEBUG("Programming ROW @%08" PRIX32, addr);
773
774 hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
775 if (hr != ERROR_OK)
776 goto exit;
777
778 hr = target_write_u32(target, wa->address, sromapi_req);
779 if (hr != ERROR_OK)
780 goto exit_free_wa;
781
782 hr = target_write_u32(target,
783 wa->address + 0x04,
784 0x106);
785 if (hr != ERROR_OK)
786 goto exit_free_wa;
787
788 hr = target_write_u32(target, wa->address + 0x08, addr);
789 if (hr != ERROR_OK)
790 goto exit_free_wa;
791
792 hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
793 if (hr != ERROR_OK)
794 goto exit_free_wa;
795
796 hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer);
797 if (hr != ERROR_OK)
798 goto exit_free_wa;
799
800 hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
801
802 exit_free_wa:
803 target_free_working_area(target, wa);
804
805 exit:
806 return hr;
807 }
808
809 /** ***********************************************************************************************
810 * @brief Performs Program operation
811 * @param bank current flash bank
812 * @param buffer pointer to the buffer with data
813 * @param offset starting offset in flash bank
814 * @param count number of bytes in buffer
815 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
816 *************************************************************************************************/
817 static int psoc6_program(struct flash_bank *bank,
818 const uint8_t *buffer,
819 uint32_t offset,
820 uint32_t count)
821 {
822 struct target *target = bank->target;
823 struct psoc6_target_info *psoc6_info = bank->driver_priv;
824 const bool is_sflash = is_sflash_bank(bank);
825 int hr;
826
827 uint8_t page_buf[psoc6_info->row_sz];
828
829 hr = sromalgo_prepare(target);
830 if (hr != ERROR_OK)
831 goto exit;
832
833 while (count) {
834 uint32_t row_offset = offset % psoc6_info->row_sz;
835 uint32_t aligned_addr = bank->base + offset - row_offset;
836 uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, count);
837
838 memset(page_buf, 0, sizeof(page_buf));
839 memcpy(&page_buf[row_offset], buffer, row_bytes);
840
841 hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash);
842 if (hr != ERROR_OK) {
843 LOG_ERROR("Failed to program Flash at address 0x%08" PRIX32, aligned_addr);
844 goto exit;
845 }
846
847 buffer += row_bytes;
848 offset += row_bytes;
849 count -= row_bytes;
850 }
851
852 exit:
853 sromalgo_release(target);
854 return hr;
855 }
856
857 /** ***********************************************************************************************
858 * @brief Performs Mass Erase operation
859 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
860 *************************************************************************************************/
861 COMMAND_HANDLER(psoc6_handle_mass_erase_command)
862 {
863 if (CMD_ARGC != 1)
864 return ERROR_COMMAND_SYNTAX_ERROR;
865
866 struct flash_bank *bank;
867 int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
868 if (hr != ERROR_OK)
869 return hr;
870
871 hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
872
873 return hr;
874 }
875
876 /** ***********************************************************************************************
877 * @brief Simulates broken Vector Catch
878 * Function will try to determine entry point of user application. If it succeeds it will set HW
879 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
880 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
881 * reset CM4 anyway, so using SYSRESETREQ is safe here.
882 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
883 *
884 * @param target current target
885 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
886 *************************************************************************************************/
887 static int handle_reset_halt(struct target *target)
888 {
889 int hr;
890 uint32_t reset_addr;
891 bool is_cm0 = (target->coreid == 0);
892
893 /* Halt target device */
894 if (target->state != TARGET_HALTED) {
895 hr = target_halt(target);
896 if (hr != ERROR_OK)
897 return hr;
898
899 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
900 if (hr != ERROR_OK)
901 return hr;
902 }
903
904 /* Read Vector Offset register */
905 uint32_t vt_base;
906 const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
907 hr = target_read_u32(target, vt_offset_reg, &vt_base);
908 if (hr != ERROR_OK)
909 return ERROR_OK;
910
911 /* Invalid value means flash is empty */
912 vt_base &= 0xFFFFFF00;
913 if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
914 return ERROR_OK;
915
916 /* Read Reset Vector value*/
917 hr = target_read_u32(target, vt_base + 4, &reset_addr);
918 if (hr != ERROR_OK)
919 return hr;
920
921 /* Invalid value means flash is empty */
922 if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
923 return ERROR_OK;
924
925
926 /* Set breakpoint at User Application entry point */
927 hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD);
928 if (hr != ERROR_OK)
929 return hr;
930
931 const struct armv7m_common *cm = target_to_armv7m(target);
932
933 /* PSoC6 reboots immediately after issuing SYSRESETREQ / VECTRESET
934 * this disables SWD/JTAG pins momentarily and may break communication
935 * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */
936 if (is_cm0) {
937 /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
938 LOG_INFO("psoc6.cm0: bkpt @0x%08" PRIX32 ", issuing SYSRESETREQ", reset_addr);
939 mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
940 AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
941 } else {
942 LOG_INFO("psoc6.cm4: bkpt @0x%08" PRIX32 ", issuing VECTRESET", reset_addr);
943 mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
944 AIRCR_VECTKEY | AIRCR_VECTRESET);
945 }
946
947 /* Wait 100ms for bootcode and reinitialize DAP */
948 usleep(100000);
949 dap_dp_init(cm->debug_ap->dap);
950
951 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
952
953 /* Remove the break point */
954 breakpoint_remove(target, reset_addr);
955
956 return ERROR_OK;
957 }
958
959 /** ***********************************************************************************************
960 * @brief Simulates broken Vector Catch
961 * Function will try to determine entry point of user application. If it succeeds it will set HW
962 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
963 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
964 * reset CM4 anyway, so using SYSRESETREQ is safe here.
965 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
966 *
967 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
968 *************************************************************************************************/
969 COMMAND_HANDLER(psoc6_handle_reset_halt)
970 {
971 if (CMD_ARGC)
972 return ERROR_COMMAND_SYNTAX_ERROR;
973
974 struct target *target = get_current_target(CMD_CTX);
975 return handle_reset_halt(target);
976 }
977
978 FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
979 {
980 struct psoc6_target_info *psoc6_info;
981 int hr = ERROR_OK;
982
983 if (CMD_ARGC < 6)
984 hr = ERROR_COMMAND_SYNTAX_ERROR;
985 else {
986 psoc6_info = calloc(1, sizeof(struct psoc6_target_info));
987 psoc6_info->is_probed = false;
988 bank->driver_priv = psoc6_info;
989 }
990 return hr;
991 }
992
993 static const struct command_registration psoc6_exec_command_handlers[] = {
994 {
995 .name = "mass_erase",
996 .handler = psoc6_handle_mass_erase_command,
997 .mode = COMMAND_EXEC,
998 .usage = "bank",
999 .help = "Erases entire Main Flash",
1000 },
1001 {
1002 .name = "reset_halt",
1003 .handler = psoc6_handle_reset_halt,
1004 .mode = COMMAND_EXEC,
1005 .usage = "",
1006 .help = "Tries to simulate broken Vector Catch",
1007 },
1008 COMMAND_REGISTRATION_DONE
1009 };
1010
1011 static const struct command_registration psoc6_command_handlers[] = {
1012 {
1013 .name = "psoc6",
1014 .mode = COMMAND_ANY,
1015 .help = "PSoC 6 flash command group",
1016 .usage = "",
1017 .chain = psoc6_exec_command_handlers,
1018 },
1019 COMMAND_REGISTRATION_DONE
1020 };
1021
1022 const struct flash_driver psoc6_flash = {
1023 .name = "psoc6",
1024 .commands = psoc6_command_handlers,
1025 .flash_bank_command = psoc6_flash_bank_command,
1026 .erase = psoc6_erase,
1027 .protect = psoc6_protect,
1028 .write = psoc6_program,
1029 .read = default_flash_read,
1030 .probe = psoc6_probe,
1031 .auto_probe = psoc6_auto_probe,
1032 .erase_check = default_flash_blank_check,
1033 .protect_check = psoc6_protect_check,
1034 .info = psoc6_get_info,
1035 .free_driver_priv = default_flash_free_driver_priv,
1036 };

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)