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

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)