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

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)