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

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)