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

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)