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