1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
5 * Copyright (C) 2018 by Bohdan Tymkiv *
6 * bohdan.tymkiv@cypress.com bohdan200@gmail.com *
7 ***************************************************************************/
16 #include "helper/time_support.h"
17 #include "target/arm_adi_v5.h"
18 #include "target/target.h"
19 #include "target/cortex_m.h"
20 #include "target/breakpoints.h"
21 #include "target/target_type.h"
22 #include "target/algorithm.h"
24 /**************************************************************************************************
25 * PSoC6 device definitions
26 *************************************************************************************************/
27 #define MFLASH_SECTOR_SIZE (256u * 1024u)
28 #define WFLASH_SECTOR_SIZE (32u * 1024u)
30 #define MEM_BASE_MFLASH 0x10000000u
31 #define MEM_BASE_WFLASH 0x14000000u
32 #define MEM_WFLASH_SIZE 32768u
33 #define MEM_BASE_SFLASH 0x16000000u
34 #define RAM_STACK_WA_SIZE 2048u
35 #define PSOC6_SPCIF_GEOMETRY 0x4025F00Cu
37 #define PROTECTION_UNKNOWN 0x00u
38 #define PROTECTION_VIRGIN 0x01u
39 #define PROTECTION_NORMAL 0x02u
40 #define PROTECTION_SECURE 0x03u
41 #define PROTECTION_DEAD 0x04u
43 #define MEM_BASE_IPC 0x40230000u
44 #define IPC_STRUCT_SIZE 0x20u
45 #define MEM_IPC(n) (MEM_BASE_IPC + (n) * IPC_STRUCT_SIZE)
46 #define MEM_IPC_ACQUIRE(n) (MEM_IPC(n) + 0x00u)
47 #define MEM_IPC_NOTIFY(n) (MEM_IPC(n) + 0x08u)
48 #define MEM_IPC_DATA(n) (MEM_IPC(n) + 0x0Cu)
49 #define MEM_IPC_LOCK_STATUS(n) (MEM_IPC(n) + 0x10u)
51 #define MEM_BASE_IPC_INTR 0x40231000u
52 #define IPC_INTR_STRUCT_SIZE 0x20u
53 #define MEM_IPC_INTR(n) (MEM_BASE_IPC_INTR + (n) * IPC_INTR_STRUCT_SIZE)
54 #define MEM_IPC_INTR_MASK(n) (MEM_IPC_INTR(n) + 0x08u)
55 #define IPC_ACQUIRE_SUCCESS_MSK 0x80000000u
56 #define IPC_LOCK_ACQUIRED_MSK 0x80000000u
59 #define IPC_INTR_ID 0u
60 #define IPC_TIMEOUT_MS 1000
62 #define SROMAPI_SIID_REQ 0x00000001u
63 #define SROMAPI_SIID_REQ_FAMILY_REVISION (SROMAPI_SIID_REQ | 0x000u)
64 #define SROMAPI_SIID_REQ_SIID_PROTECTION (SROMAPI_SIID_REQ | 0x100u)
65 #define SROMAPI_WRITEROW_REQ 0x05000100u
66 #define SROMAPI_PROGRAMROW_REQ 0x06000100u
67 #define SROMAPI_ERASESECTOR_REQ 0x14000100u
68 #define SROMAPI_ERASEALL_REQ 0x0A000100u
69 #define SROMAPI_ERASEROW_REQ 0x1C000100u
71 #define SROMAPI_STATUS_MSK 0xF0000000u
72 #define SROMAPI_STAT_SUCCESS 0xA0000000u
73 #define SROMAPI_DATA_LOCATION_MSK 0x00000001u
74 #define SROMAPI_CALL_TIMEOUT_MS 1500
76 struct psoc6_target_info
{
79 uint32_t main_flash_sz
;
94 static const struct row_region safe_sflash_regions
[] = {
95 {0x16000800, 0x800}, /* SFLASH: User Data */
96 {0x16001A00, 0x200}, /* SFLASH: NAR */
97 {0x16005A00, 0xC00}, /* SFLASH: Public Key */
98 {0x16007C00, 0x400}, /* SFLASH: TOC2 */
101 #define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
103 static struct working_area
*g_stack_area
;
104 static struct armv7m_algorithm g_armv7m_info
;
106 /** ***********************************************************************************************
107 * @brief Initializes `struct timeout` structure with given timeout value
108 * @param to pointer to `struct timeout` structure
109 * @param timeout_ms timeout, in milliseconds
110 *************************************************************************************************/
111 static void timeout_init(struct timeout
*to
, long timeout_ms
)
113 to
->start_time
= timeval_ms();
114 to
->timeout_ms
= timeout_ms
;
117 /** ***********************************************************************************************
118 * @brief Returns true if given `struct timeout` structure has expired
119 * @param to pointer to `struct timeout` structure
120 * @return true if timeout expired
121 *************************************************************************************************/
122 static bool timeout_expired(struct timeout
*to
)
124 return (timeval_ms() - to
->start_time
) > to
->timeout_ms
;
127 /** ***********************************************************************************************
128 * @brief Starts pseudo flash algorithm and leaves it running. Function allocates working area for
129 * algorithm code and CPU stack, adjusts stack pointer, uploads and starts the algorithm.
130 * Algorithm (a basic infinite loop) runs asynchronously while driver performs Flash operations.
132 * @param target target for the algorithm
133 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
134 *************************************************************************************************/
135 static int sromalgo_prepare(struct target
*target
)
139 /* Initialize Vector Table Offset register (in case FW modified it) */
140 hr
= target_write_u32(target
, 0xE000ED08, 0x00000000);
144 /* Allocate Working Area for Stack and Flash algorithm */
145 hr
= target_alloc_working_area(target
, RAM_STACK_WA_SIZE
, &g_stack_area
);
149 g_armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
150 g_armv7m_info
.core_mode
= ARM_MODE_THREAD
;
152 struct reg_param reg_params
;
153 init_reg_param(®_params
, "sp", 32, PARAM_OUT
);
154 buf_set_u32(reg_params
.value
, 0, 32, g_stack_area
->address
+ g_stack_area
->size
);
156 /* Write basic infinite loop algorithm to target RAM */
157 hr
= target_write_u32(target
, g_stack_area
->address
, 0xFEE7FEE7);
159 goto destroy_rp_free_wa
;
161 hr
= target_start_algorithm(target
, 0, NULL
, 1, ®_params
, g_stack_area
->address
,
164 goto destroy_rp_free_wa
;
166 destroy_reg_param(®_params
);
171 /* Something went wrong, do some cleanup */
172 destroy_reg_param(®_params
);
174 target_free_working_area(target
, g_stack_area
);
180 /** ***********************************************************************************************
181 * @brief Stops running flash algorithm and releases associated resources.
182 * This function is also used for cleanup in case of errors so g_stack_area may be NULL.
183 * These cases have to be handled gracefully.
185 * @param target current target
186 *************************************************************************************************/
187 static void sromalgo_release(struct target
*target
)
192 /* Stop flash algorithm if it is running */
193 if (target
->running_alg
) {
194 hr
= target_halt(target
);
198 hr
= target_wait_algorithm(target
, 0, NULL
, 0, NULL
, 0,
199 IPC_TIMEOUT_MS
, &g_armv7m_info
);
205 /* Free Stack/Flash algorithm working area */
206 target_free_working_area(target
, g_stack_area
);
211 /** ***********************************************************************************************
212 * @brief Waits for expected IPC lock status. PSoC6 uses IPC structures for inter-core
213 * communication. Same IPCs are used to invoke SROM API. IPC structure must be locked prior to
214 * invoking any SROM API. This ensures nothing else in the system will use same IPC thus corrupting
215 * our data. Locking is performed by ipc_acquire(), this function ensures that IPC is actually
218 * @param target current target
219 * @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access
220 * @param lock_expected expected lock status
221 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
222 *************************************************************************************************/
223 static int ipc_poll_lock_stat(struct target
*target
, uint32_t ipc_id
, bool lock_expected
)
229 timeout_init(&to
, IPC_TIMEOUT_MS
);
231 while (!timeout_expired(&to
)) {
232 /* Process any server requests */
235 /* Read IPC Lock status */
236 hr
= target_read_u32(target
, MEM_IPC_LOCK_STATUS(ipc_id
), ®_val
);
237 if (hr
!= ERROR_OK
) {
238 LOG_ERROR("Unable to read IPC Lock Status register");
242 bool is_locked
= (reg_val
& IPC_LOCK_ACQUIRED_MSK
) != 0;
244 if (lock_expected
== is_locked
)
248 if (target
->coreid
) {
249 LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. "
250 "Please perform all Flash-related operations via CM0+ target on dual-core devices.");
253 LOG_ERROR("Timeout polling IPC Lock Status");
254 return ERROR_TARGET_TIMEOUT
;
257 /** ***********************************************************************************************
258 * @brief Acquires IPC structure. PSoC6 uses IPC structures for inter-core communication.
259 * Same IPCs are used to invoke SROM API. IPC structure must be locked prior to invoking any SROM API.
260 * This ensures nothing else in the system will use same IPC thus corrupting our data.
261 * This function locks the IPC.
263 * @param target current target
264 * @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP access
265 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
266 *************************************************************************************************/
267 static int ipc_acquire(struct target
*target
, char ipc_id
)
270 bool is_acquired
= false;
274 timeout_init(&to
, IPC_TIMEOUT_MS
);
276 while (!timeout_expired(&to
)) {
279 hr
= target_write_u32(target
, MEM_IPC_ACQUIRE(ipc_id
), IPC_ACQUIRE_SUCCESS_MSK
);
280 if (hr
!= ERROR_OK
) {
281 LOG_ERROR("Unable to write to IPC Acquire register");
285 /* Check if data is written on first step */
286 hr
= target_read_u32(target
, MEM_IPC_ACQUIRE(ipc_id
), ®_val
);
287 if (hr
!= ERROR_OK
) {
288 LOG_ERROR("Unable to read IPC Acquire register");
292 is_acquired
= (reg_val
& IPC_ACQUIRE_SUCCESS_MSK
) != 0;
294 /* If IPC structure is acquired, the lock status should be set */
295 hr
= ipc_poll_lock_stat(target
, ipc_id
, true);
301 LOG_ERROR("Timeout acquiring IPC structure");
306 /** ***********************************************************************************************
307 * @brief Invokes SROM API functions which are responsible for Flash operations
309 * @param target current target
310 * @param req_and_params request id of the function to invoke
311 * @param working_area address of memory buffer in target's memory space for SROM API parameters
312 * @param data_out pointer to variable which will be populated with execution status
313 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
314 *************************************************************************************************/
315 static int call_sromapi(struct target
*target
,
316 uint32_t req_and_params
,
317 uint32_t working_area
,
322 bool is_data_in_ram
= (req_and_params
& SROMAPI_DATA_LOCATION_MSK
) == 0;
324 hr
= ipc_acquire(target
, IPC_ID
);
329 hr
= target_write_u32(target
, MEM_IPC_DATA(IPC_ID
), working_area
);
331 hr
= target_write_u32(target
, MEM_IPC_DATA(IPC_ID
), req_and_params
);
336 /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */
337 hr
= target_write_u32(target
, MEM_IPC_INTR_MASK(IPC_INTR_ID
), 1u << (16 + IPC_ID
));
341 hr
= target_write_u32(target
, MEM_IPC_NOTIFY(IPC_ID
), 1);
345 /* Poll lock status */
346 hr
= ipc_poll_lock_stat(target
, IPC_ID
, false);
352 hr
= target_read_u32(target
, working_area
, data_out
);
354 hr
= target_read_u32(target
, MEM_IPC_DATA(IPC_ID
), data_out
);
356 if (hr
!= ERROR_OK
) {
357 LOG_ERROR("Error reading SROM API Status location");
361 bool is_success
= (*data_out
& SROMAPI_STATUS_MSK
) == SROMAPI_STAT_SUCCESS
;
363 LOG_ERROR("SROM API execution failed. Status: 0x%08" PRIX32
, *data_out
);
364 return ERROR_TARGET_FAILURE
;
370 /** ***********************************************************************************************
371 * @brief Retrieves SiliconID and Protection status of the target device
372 * @param target current target
373 * @param si_id pointer to variable, will be populated with SiliconID
374 * @param protection pointer to variable, will be populated with protection status
375 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
376 *************************************************************************************************/
377 static int get_silicon_id(struct target
*target
, uint32_t *si_id
, uint8_t *protection
)
380 uint32_t family_rev
, siid_prot
;
382 hr
= sromalgo_prepare(target
);
386 /* Read FamilyID and Revision */
387 hr
= call_sromapi(target
, SROMAPI_SIID_REQ_FAMILY_REVISION
, 0, &family_rev
);
391 /* Read SiliconID and Protection */
392 hr
= call_sromapi(target
, SROMAPI_SIID_REQ_SIID_PROTECTION
, 0, &siid_prot
);
396 *si_id
= (siid_prot
& 0x0000FFFF) << 16;
397 *si_id
|= (family_rev
& 0x00FF0000) >> 8;
398 *si_id
|= (family_rev
& 0x000000FF) >> 0;
400 *protection
= (siid_prot
& 0x000F0000) >> 0x10;
403 sromalgo_release(target
);
407 /** ***********************************************************************************************
408 * @brief Translates Protection status to openocd-friendly boolean value
409 * @param bank current flash bank
410 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
411 *************************************************************************************************/
412 static int psoc6_protect_check(struct flash_bank
*bank
)
416 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
417 int hr
= get_silicon_id(bank
->target
, &psoc6_info
->silicon_id
, &psoc6_info
->protection
);
421 switch (psoc6_info
->protection
) {
422 case PROTECTION_VIRGIN
:
423 case PROTECTION_NORMAL
:
427 case PROTECTION_UNKNOWN
:
428 case PROTECTION_SECURE
:
429 case PROTECTION_DEAD
:
435 for (unsigned int i
= 0; i
< bank
->num_sectors
; i
++)
436 bank
->sectors
[i
].is_protected
= is_protected
;
441 /** ***********************************************************************************************
442 * @brief Dummy function, Life Cycle transition is not currently supported
443 * @return ERROR_OK always
444 *************************************************************************************************/
445 static int psoc6_protect(struct flash_bank
*bank
, int set
, unsigned int first
,
453 LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
457 /** ***********************************************************************************************
458 * @brief Translates Protection status to string
459 * @param protection protection value
460 * @return pointer to const string describing protection status
461 *************************************************************************************************/
462 static const char *protection_to_str(uint8_t protection
)
464 switch (protection
) {
465 case PROTECTION_VIRGIN
:
467 case PROTECTION_NORMAL
:
469 case PROTECTION_SECURE
:
471 case PROTECTION_DEAD
:
473 case PROTECTION_UNKNOWN
:
479 /** ***********************************************************************************************
480 * @brief psoc6_get_info Displays human-readable information about acquired device
481 * @param bank current flash bank
482 * @param cmd pointer to command invocation instance
483 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
484 *************************************************************************************************/
485 static int psoc6_get_info(struct flash_bank
*bank
, struct command_invocation
*cmd
)
487 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
489 if (psoc6_info
->is_probed
== false)
492 int hr
= get_silicon_id(bank
->target
, &psoc6_info
->silicon_id
, &psoc6_info
->protection
);
496 command_print_sameline(cmd
,
497 "PSoC6 Silicon ID: 0x%08" PRIX32
"\n"
499 "Main Flash size: %" PRIu32
" kB\n"
500 "Work Flash size: 32 kB\n",
501 psoc6_info
->silicon_id
,
502 protection_to_str(psoc6_info
->protection
),
503 psoc6_info
->main_flash_sz
/ 1024);
508 /** ***********************************************************************************************
509 * @brief Checks if given flash bank belongs to Supervisory Flash
510 * @param bank current flash bank
511 * @return true if flash bank belongs to Supervisory Flash
512 *************************************************************************************************/
513 static bool is_sflash_bank(struct flash_bank
*bank
)
515 for (size_t i
= 0; i
< SFLASH_NUM_REGIONS
; i
++) {
516 if (bank
->base
== safe_sflash_regions
[i
].addr
)
523 /** ***********************************************************************************************
524 * @brief Checks if given flash bank belongs to Work Flash
525 * @param bank current flash bank
526 * @return true if flash bank belongs to Work Flash
527 *************************************************************************************************/
528 static inline bool is_wflash_bank(struct flash_bank
*bank
)
530 return (bank
->base
== MEM_BASE_WFLASH
);
533 /** ***********************************************************************************************
534 * @brief Checks if given flash bank belongs to Main Flash
535 * @param bank current flash bank
536 * @return true if flash bank belongs to Main Flash
537 *************************************************************************************************/
538 static inline bool is_mflash_bank(struct flash_bank
*bank
)
540 return (bank
->base
== MEM_BASE_MFLASH
);
543 /** ***********************************************************************************************
544 * @brief Probes the device and populates related data structures with target flash geometry data.
545 * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a
546 * running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers)
548 * @param bank current flash bank
549 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
550 *************************************************************************************************/
551 static int psoc6_probe(struct flash_bank
*bank
)
553 struct target
*target
= bank
->target
;
554 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
558 /* Retrieve data from SPCIF_GEOMETRY */
560 target_read_u32(target
, PSOC6_SPCIF_GEOMETRY
, &geom
);
561 uint32_t row_sz_lg2
= (geom
& 0xF0) >> 4;
562 uint32_t row_sz
= (0x01 << row_sz_lg2
);
563 uint32_t row_cnt
= 1 + ((geom
& 0x00FFFF00) >> 8);
564 uint32_t bank_cnt
= 1 + ((geom
& 0xFF000000) >> 24);
566 /* Calculate size of Main Flash*/
567 uint32_t flash_sz_bytes
= bank_cnt
* row_cnt
* row_sz
;
570 bank
->sectors
= NULL
;
572 size_t bank_size
= 0;
574 if (is_mflash_bank(bank
))
575 bank_size
= flash_sz_bytes
;
576 else if (is_wflash_bank(bank
))
577 bank_size
= MEM_WFLASH_SIZE
;
578 else if (is_sflash_bank(bank
)) {
579 for (size_t i
= 0; i
< SFLASH_NUM_REGIONS
; i
++) {
580 if (safe_sflash_regions
[i
].addr
== bank
->base
) {
581 bank_size
= safe_sflash_regions
[i
].size
;
587 if (bank_size
== 0) {
588 LOG_ERROR("Invalid Flash Bank base address in config file");
589 return ERROR_FLASH_BANK_INVALID
;
592 unsigned int num_sectors
= bank_size
/ row_sz
;
593 bank
->size
= bank_size
;
595 bank
->erased_value
= 0;
596 bank
->default_padded_value
= 0;
598 bank
->num_sectors
= num_sectors
;
599 bank
->sectors
= calloc(num_sectors
, sizeof(struct flash_sector
));
600 for (unsigned int i
= 0; i
< num_sectors
; i
++) {
601 bank
->sectors
[i
].size
= row_sz
;
602 bank
->sectors
[i
].offset
= i
* row_sz
;
603 bank
->sectors
[i
].is_erased
= -1;
604 bank
->sectors
[i
].is_protected
= -1;
607 psoc6_info
->is_probed
= true;
608 psoc6_info
->main_flash_sz
= flash_sz_bytes
;
609 psoc6_info
->row_sz
= row_sz
;
614 /** ***********************************************************************************************
615 * @brief Probes target device only if it hasn't been probed yet
616 * @param bank current flash bank
617 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
618 *************************************************************************************************/
619 static int psoc6_auto_probe(struct flash_bank
*bank
)
621 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
624 if (psoc6_info
->is_probed
)
627 hr
= psoc6_probe(bank
);
632 /** ***********************************************************************************************
633 * @brief Erases single sector (256k) on target device
634 * @param bank current flash bank
635 * @param wa working area for SROM API parameters
636 * @param addr starting address of the sector
637 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
638 *************************************************************************************************/
639 static int psoc6_erase_sector(struct flash_bank
*bank
, struct working_area
*wa
, uint32_t addr
)
641 struct target
*target
= bank
->target
;
643 LOG_DEBUG("Erasing SECTOR @%08" PRIX32
, addr
);
645 int hr
= target_write_u32(target
, wa
->address
, SROMAPI_ERASESECTOR_REQ
);
649 hr
= target_write_u32(target
, wa
->address
+ 0x04, addr
);
654 hr
= call_sromapi(target
, SROMAPI_ERASESECTOR_REQ
, wa
->address
, &data_out
);
656 LOG_ERROR("SECTOR @%08" PRIX32
" not erased!", addr
);
661 /** ***********************************************************************************************
662 * @brief Erases single row (512b) on target device
663 * @param bank current flash bank
664 * @param wa working area for SROM API parameters
665 * @param addr starting address of the flash row
666 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
667 *************************************************************************************************/
668 static int psoc6_erase_row(struct flash_bank
*bank
, struct working_area
*wa
, uint32_t addr
)
670 struct target
*target
= bank
->target
;
672 LOG_DEBUG("Erasing ROW @%08" PRIX32
, addr
);
674 int hr
= target_write_u32(target
, wa
->address
, SROMAPI_ERASEROW_REQ
);
678 hr
= target_write_u32(target
, wa
->address
+ 0x04, addr
);
683 hr
= call_sromapi(target
, SROMAPI_ERASEROW_REQ
, wa
->address
, &data_out
);
685 LOG_ERROR("ROW @%08" PRIX32
" not erased!", addr
);
690 /** ***********************************************************************************************
691 * @brief Performs Erase operation. Function will try to use biggest erase block possible to
692 * speedup the operation.
694 * @param bank current flash bank
695 * @param first first sector to erase
696 * @param last last sector to erase
697 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
698 *************************************************************************************************/
699 static int psoc6_erase(struct flash_bank
*bank
, unsigned int first
,
702 struct target
*target
= bank
->target
;
703 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
704 const uint32_t sector_size
= is_wflash_bank(bank
) ? WFLASH_SECTOR_SIZE
: MFLASH_SECTOR_SIZE
;
707 struct working_area
*wa
;
709 if (is_sflash_bank(bank
)) {
710 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
714 hr
= sromalgo_prepare(target
);
718 hr
= target_alloc_working_area(target
, psoc6_info
->row_sz
+ 32, &wa
);
722 /* Number of rows in single sector */
723 const unsigned int rows_in_sector
= sector_size
/ psoc6_info
->row_sz
;
725 while (last
>= first
) {
726 /* Erase Sector if we are on sector boundary and erase size covers whole sector */
727 if ((first
% rows_in_sector
) == 0 &&
728 (last
- first
+ 1) >= rows_in_sector
) {
729 hr
= psoc6_erase_sector(bank
, wa
, bank
->base
+ first
* psoc6_info
->row_sz
);
733 first
+= rows_in_sector
;
735 /* Perform Row Erase otherwise */
736 hr
= psoc6_erase_row(bank
, wa
, bank
->base
+ first
* psoc6_info
->row_sz
);
745 target_free_working_area(target
, wa
);
747 sromalgo_release(target
);
751 /** ***********************************************************************************************
752 * @brief Programs single Flash Row
753 * @param bank current flash bank
754 * @param addr address of the flash row
755 * @param buffer pointer to the buffer with data
756 * @param is_sflash true if current flash bank belongs to Supervisory Flash
757 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
758 *************************************************************************************************/
759 static int psoc6_program_row(struct flash_bank
*bank
,
761 const uint8_t *buffer
,
764 struct target
*target
= bank
->target
;
765 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
766 struct working_area
*wa
;
767 const uint32_t sromapi_req
= is_sflash
? SROMAPI_WRITEROW_REQ
: SROMAPI_PROGRAMROW_REQ
;
771 LOG_DEBUG("Programming ROW @%08" PRIX32
, addr
);
773 hr
= target_alloc_working_area(target
, psoc6_info
->row_sz
+ 32, &wa
);
777 hr
= target_write_u32(target
, wa
->address
, sromapi_req
);
781 hr
= target_write_u32(target
,
787 hr
= target_write_u32(target
, wa
->address
+ 0x08, addr
);
791 hr
= target_write_u32(target
, wa
->address
+ 0x0C, wa
->address
+ 0x10);
795 hr
= target_write_buffer(target
, wa
->address
+ 0x10, psoc6_info
->row_sz
, buffer
);
799 hr
= call_sromapi(target
, sromapi_req
, wa
->address
, &data_out
);
802 target_free_working_area(target
, wa
);
808 /** ***********************************************************************************************
809 * @brief Performs Program operation
810 * @param bank current flash bank
811 * @param buffer pointer to the buffer with data
812 * @param offset starting offset in flash bank
813 * @param count number of bytes in buffer
814 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
815 *************************************************************************************************/
816 static int psoc6_program(struct flash_bank
*bank
,
817 const uint8_t *buffer
,
821 struct target
*target
= bank
->target
;
822 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
823 const bool is_sflash
= is_sflash_bank(bank
);
826 uint8_t page_buf
[psoc6_info
->row_sz
];
828 hr
= sromalgo_prepare(target
);
833 uint32_t row_offset
= offset
% psoc6_info
->row_sz
;
834 uint32_t aligned_addr
= bank
->base
+ offset
- row_offset
;
835 uint32_t row_bytes
= MIN(psoc6_info
->row_sz
- row_offset
, count
);
837 memset(page_buf
, 0, sizeof(page_buf
));
838 memcpy(&page_buf
[row_offset
], buffer
, row_bytes
);
840 hr
= psoc6_program_row(bank
, aligned_addr
, page_buf
, is_sflash
);
841 if (hr
!= ERROR_OK
) {
842 LOG_ERROR("Failed to program Flash at address 0x%08" PRIX32
, aligned_addr
);
852 sromalgo_release(target
);
856 /** ***********************************************************************************************
857 * @brief Performs Mass Erase operation
858 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
859 *************************************************************************************************/
860 COMMAND_HANDLER(psoc6_handle_mass_erase_command
)
863 return ERROR_COMMAND_SYNTAX_ERROR
;
865 struct flash_bank
*bank
;
866 int hr
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
870 hr
= psoc6_erase(bank
, 0, bank
->num_sectors
- 1);
875 /** ***********************************************************************************************
876 * @brief Simulates broken Vector Catch
877 * Function will try to determine entry point of user application. If it succeeds it will set HW
878 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
879 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
880 * reset CM4 anyway, so using SYSRESETREQ is safe here.
881 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
883 * @param target current target
884 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
885 *************************************************************************************************/
886 static int handle_reset_halt(struct target
*target
)
890 bool is_cm0
= (target
->coreid
== 0);
892 /* Halt target device */
893 if (target
->state
!= TARGET_HALTED
) {
894 hr
= target_halt(target
);
898 target_wait_state(target
, TARGET_HALTED
, IPC_TIMEOUT_MS
);
903 /* Read Vector Offset register */
905 const uint32_t vt_offset_reg
= is_cm0
? 0x402102B0 : 0x402102C0;
906 hr
= target_read_u32(target
, vt_offset_reg
, &vt_base
);
910 /* Invalid value means flash is empty */
911 vt_base
&= 0xFFFFFF00;
912 if ((vt_base
== 0) || (vt_base
== 0xFFFFFF00))
915 /* Read Reset Vector value*/
916 hr
= target_read_u32(target
, vt_base
+ 4, &reset_addr
);
920 /* Invalid value means flash is empty */
921 if ((reset_addr
== 0) || (reset_addr
== 0xFFFFFF00))
925 /* Set breakpoint at User Application entry point */
926 hr
= breakpoint_add(target
, reset_addr
, 2, BKPT_HARD
);
930 const struct armv7m_common
*cm
= target_to_armv7m(target
);
932 /* PSoC6 reboots immediately after issuing SYSRESETREQ / VECTRESET
933 * this disables SWD/JTAG pins momentarily and may break communication
934 * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */
936 /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
937 LOG_INFO("psoc6.cm0: bkpt @0x%08" PRIX32
", issuing SYSRESETREQ", reset_addr
);
938 mem_ap_write_atomic_u32(cm
->debug_ap
, NVIC_AIRCR
,
939 AIRCR_VECTKEY
| AIRCR_SYSRESETREQ
);
941 LOG_INFO("psoc6.cm4: bkpt @0x%08" PRIX32
", issuing VECTRESET", reset_addr
);
942 mem_ap_write_atomic_u32(cm
->debug_ap
, NVIC_AIRCR
,
943 AIRCR_VECTKEY
| AIRCR_VECTRESET
);
946 /* Wait 100ms for bootcode and reinitialize DAP */
948 dap_dp_init(cm
->debug_ap
->dap
);
950 target_wait_state(target
, TARGET_HALTED
, IPC_TIMEOUT_MS
);
952 /* Remove the break point */
953 breakpoint_remove(target
, reset_addr
);
958 /** ***********************************************************************************************
959 * @brief Simulates broken Vector Catch
960 * Function will try to determine entry point of user application. If it succeeds it will set HW
961 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
962 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
963 * reset CM4 anyway, so using SYSRESETREQ is safe here.
964 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
966 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
967 *************************************************************************************************/
968 COMMAND_HANDLER(psoc6_handle_reset_halt
)
971 return ERROR_COMMAND_SYNTAX_ERROR
;
973 struct target
*target
= get_current_target(CMD_CTX
);
974 return handle_reset_halt(target
);
977 FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command
)
979 struct psoc6_target_info
*psoc6_info
;
983 hr
= ERROR_COMMAND_SYNTAX_ERROR
;
985 psoc6_info
= calloc(1, sizeof(struct psoc6_target_info
));
986 psoc6_info
->is_probed
= false;
987 bank
->driver_priv
= psoc6_info
;
992 static const struct command_registration psoc6_exec_command_handlers
[] = {
994 .name
= "mass_erase",
995 .handler
= psoc6_handle_mass_erase_command
,
996 .mode
= COMMAND_EXEC
,
998 .help
= "Erases entire Main Flash",
1001 .name
= "reset_halt",
1002 .handler
= psoc6_handle_reset_halt
,
1003 .mode
= COMMAND_EXEC
,
1005 .help
= "Tries to simulate broken Vector Catch",
1007 COMMAND_REGISTRATION_DONE
1010 static const struct command_registration psoc6_command_handlers
[] = {
1013 .mode
= COMMAND_ANY
,
1014 .help
= "PSoC 6 flash command group",
1016 .chain
= psoc6_exec_command_handlers
,
1018 COMMAND_REGISTRATION_DONE
1021 const struct flash_driver psoc6_flash
= {
1023 .commands
= psoc6_command_handlers
,
1024 .flash_bank_command
= psoc6_flash_bank_command
,
1025 .erase
= psoc6_erase
,
1026 .protect
= psoc6_protect
,
1027 .write
= psoc6_program
,
1028 .read
= default_flash_read
,
1029 .probe
= psoc6_probe
,
1030 .auto_probe
= psoc6_auto_probe
,
1031 .erase_check
= default_flash_blank_check
,
1032 .protect_check
= psoc6_protect_check
,
1033 .info
= psoc6_get_info
,
1034 .free_driver_priv
= default_flash_free_driver_priv
,