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

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)