1 /***************************************************************************
3 * Copyright (C) 2018 by Bohdan Tymkiv *
4 * bohdan.tymkiv@cypress.com bohdan200@gmail.com *
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. *
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. *
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 ***************************************************************************/
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"
34 /**************************************************************************************************
35 * PSoC6 device definitions
36 *************************************************************************************************/
37 #define MFLASH_SECTOR_SIZE (256u * 1024u)
38 #define WFLASH_SECTOR_SIZE (32u * 1024u)
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
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
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)
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
69 #define IPC_INTR_ID 0u
70 #define IPC_TIMEOUT_MS 1000
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
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
86 struct psoc6_target_info
{
89 uint32_t main_flash_sz
;
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 */
111 #define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
113 static struct working_area
*g_stack_area
;
114 static struct armv7m_algorithm g_armv7m_info
;
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
)
123 to
->start_time
= timeval_ms();
124 to
->timeout_ms
= timeout_ms
;
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
)
134 return (timeval_ms() - to
->start_time
) > to
->timeout_ms
;
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.
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
)
149 /* Initialize Vector Table Offset register (in case FW modified it) */
150 hr
= target_write_u32(target
, 0xE000ED08, 0x00000000);
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);
160 /* Allocate Working Area for Stack and Flash algorithm */
161 hr
= target_alloc_working_area(target
, RAM_STACK_WA_SIZE
, &g_stack_area
);
165 g_armv7m_info
.common_magic
= ARMV7M_COMMON_MAGIC
;
166 g_armv7m_info
.core_mode
= ARM_MODE_THREAD
;
168 struct reg_param reg_params
;
169 init_reg_param(®_params
, "sp", 32, PARAM_OUT
);
170 buf_set_u32(reg_params
.value
, 0, 32, g_stack_area
->address
+ g_stack_area
->size
);
172 /* Write basic infinite loop algorithm to target RAM */
173 hr
= target_write_u32(target
, g_stack_area
->address
, 0xFEE7FEE7);
175 goto destroy_rp_free_wa
;
177 hr
= target_start_algorithm(target
, 0, NULL
, 1, ®_params
, g_stack_area
->address
,
180 goto destroy_rp_free_wa
;
182 destroy_reg_param(®_params
);
187 /* Something went wrong, do some cleanup */
188 destroy_reg_param(®_params
);
191 target_free_working_area(target
, g_stack_area
);
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.
203 * @param target current target
204 *************************************************************************************************/
205 static void sromalgo_release(struct target
*target
)
210 /* Stop flash algorithm if it is running */
211 if (target
->running_alg
) {
212 hr
= target_halt(target
);
216 hr
= target_wait_algorithm(target
, 0, NULL
, 0, NULL
, 0,
217 IPC_TIMEOUT_MS
, &g_armv7m_info
);
223 /* Free Stack/Flash algorithm working area */
224 target_free_working_area(target
, g_stack_area
);
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
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
)
247 timeout_init(&to
, IPC_TIMEOUT_MS
);
249 while (!timeout_expired(&to
)) {
250 /* Process any server requests */
253 /* Read IPC Lock status */
254 hr
= target_read_u32(target
, MEM_IPC_LOCK_STATUS(ipc_id
), ®_val
);
255 if (hr
!= ERROR_OK
) {
256 LOG_ERROR("Unable to read IPC Lock Status register");
260 bool is_locked
= (reg_val
& IPC_LOCK_ACQUIRED_MSK
) != 0;
262 if (lock_expected
== is_locked
)
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.");
271 LOG_ERROR("Timeout polling IPC Lock Status");
272 return ERROR_TARGET_TIMEOUT
;
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.
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
)
288 bool is_acquired
= false;
292 timeout_init(&to
, IPC_TIMEOUT_MS
);
294 while (!timeout_expired(&to
)) {
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");
303 /* Check if data is written on first step */
304 hr
= target_read_u32(target
, MEM_IPC_ACQUIRE(ipc_id
), ®_val
);
305 if (hr
!= ERROR_OK
) {
306 LOG_ERROR("Unable to read IPC Acquire register");
310 is_acquired
= (reg_val
& IPC_ACQUIRE_SUCCESS_MSK
) != 0;
312 /* If IPC structure is acquired, the lock status should be set */
313 hr
= ipc_poll_lock_stat(target
, ipc_id
, true);
319 LOG_ERROR("Timeout acquiring IPC structure");
324 /** ***********************************************************************************************
325 * @brief Invokes SROM API functions which are responsible for Flash operations
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
,
340 bool is_data_in_ram
= (req_and_params
& SROMAPI_DATA_LOCATION_MSK
) == 0;
342 hr
= ipc_acquire(target
, IPC_ID
);
347 hr
= target_write_u32(target
, MEM_IPC_DATA(IPC_ID
), working_area
);
349 hr
= target_write_u32(target
, MEM_IPC_DATA(IPC_ID
), req_and_params
);
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
));
359 hr
= target_write_u32(target
, MEM_IPC_NOTIFY(IPC_ID
), 1);
363 /* Poll lock status */
364 hr
= ipc_poll_lock_stat(target
, IPC_ID
, false);
370 hr
= target_read_u32(target
, working_area
, data_out
);
372 hr
= target_read_u32(target
, MEM_IPC_DATA(IPC_ID
), data_out
);
374 if (hr
!= ERROR_OK
) {
375 LOG_ERROR("Error reading SROM API Status location");
379 bool is_success
= (*data_out
& SROMAPI_STATUS_MSK
) == SROMAPI_STAT_SUCCESS
;
381 LOG_ERROR("SROM API execution failed. Status: 0x%08X", (uint32_t)*data_out
);
382 return ERROR_TARGET_FAILURE
;
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
)
398 uint32_t family_rev
, siid_prot
;
400 hr
= sromalgo_prepare(target
);
404 /* Read FamilyID and Revision */
405 hr
= call_sromapi(target
, SROMAPI_SIID_REQ_FAMILY_REVISION
, 0, &family_rev
);
409 /* Read SiliconID and Protection */
410 hr
= call_sromapi(target
, SROMAPI_SIID_REQ_SIID_PROTECTION
, 0, &siid_prot
);
414 *si_id
= (siid_prot
& 0x0000FFFF) << 16;
415 *si_id
|= (family_rev
& 0x00FF0000) >> 8;
416 *si_id
|= (family_rev
& 0x000000FF) >> 0;
418 *protection
= (siid_prot
& 0x000F0000) >> 0x10;
421 sromalgo_release(target
);
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
)
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
);
439 switch (psoc6_info
->protection
) {
440 case PROTECTION_VIRGIN
:
441 case PROTECTION_NORMAL
:
445 case PROTECTION_UNKNOWN
:
446 case PROTECTION_SECURE
:
447 case PROTECTION_DEAD
:
453 for (unsigned int i
= 0; i
< bank
->num_sectors
; i
++)
454 bank
->sectors
[i
].is_protected
= is_protected
;
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
, unsigned int first
,
471 LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
475 /** ***********************************************************************************************
476 * @brief Translates Protection status to string
477 * @param protection protection value
478 * @return pointer to const string describintg protection status
479 *************************************************************************************************/
480 static const char *protection_to_str(uint8_t protection
)
482 switch (protection
) {
483 case PROTECTION_VIRGIN
:
485 case PROTECTION_NORMAL
:
487 case PROTECTION_SECURE
:
489 case PROTECTION_DEAD
:
491 case PROTECTION_UNKNOWN
:
497 /** ***********************************************************************************************
498 * @brief psoc6_get_info Displays human-readable information about acquired device
499 * @param bank current flash bank
500 * @param buf pointer to buffer for human-readable text
501 * @param buf_size size of the buffer
502 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
503 *************************************************************************************************/
504 static int psoc6_get_info(struct flash_bank
*bank
, char *buf
, int buf_size
)
506 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
508 if (psoc6_info
->is_probed
== false)
511 int hr
= get_silicon_id(bank
->target
, &psoc6_info
->silicon_id
, &psoc6_info
->protection
);
515 snprintf(buf
, buf_size
,
516 "PSoC6 Silicon ID: 0x%08X\n"
518 "Main Flash size: %d kB\n"
519 "Work Flash size: 32 kB\n",
520 psoc6_info
->silicon_id
,
521 protection_to_str(psoc6_info
->protection
),
522 psoc6_info
->main_flash_sz
/ 1024);
527 /** ***********************************************************************************************
528 * @brief Checks if given flash bank belongs to Supervisory Flash
529 * @param bank current flash bank
530 * @return true if flash bank belongs to Supervisory Flash
531 *************************************************************************************************/
532 static bool is_sflash_bank(struct flash_bank
*bank
)
534 for (size_t i
= 0; i
< SFLASH_NUM_REGIONS
; i
++) {
535 if (bank
->base
== safe_sflash_regions
[i
].addr
)
542 /** ***********************************************************************************************
543 * @brief Checks if given flash bank belongs to Work Flash
544 * @param bank current flash bank
545 * @return true if flash bank belongs to Work Flash
546 *************************************************************************************************/
547 static inline bool is_wflash_bank(struct flash_bank
*bank
)
549 return (bank
->base
== MEM_BASE_WFLASH
);
552 /** ***********************************************************************************************
553 * @brief Checks if given flash bank belongs to Main Flash
554 * @param bank current flash bank
555 * @return true if flash bank belongs to Main Flash
556 *************************************************************************************************/
557 static inline bool is_mflash_bank(struct flash_bank
*bank
)
559 return (bank
->base
== MEM_BASE_MFLASH
);
562 /** ***********************************************************************************************
563 * @brief Probes the device and populates related data structures with target flash geometry data.
564 * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a
565 * running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers)
567 * @param bank current flash bank
568 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
569 *************************************************************************************************/
570 static int psoc6_probe(struct flash_bank
*bank
)
572 struct target
*target
= bank
->target
;
573 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
577 /* Retrieve data from SPCIF_GEOMATRY */
579 target_read_u32(target
, PSOC6_SPCIF_GEOMETRY
, &geom
);
580 uint32_t row_sz_lg2
= (geom
& 0xF0) >> 4;
581 uint32_t row_sz
= (0x01 << row_sz_lg2
);
582 uint32_t row_cnt
= 1 + ((geom
& 0x00FFFF00) >> 8);
583 uint32_t bank_cnt
= 1 + ((geom
& 0xFF000000) >> 24);
585 /* Calculate size of Main Flash*/
586 uint32_t flash_sz_bytes
= bank_cnt
* row_cnt
* row_sz
;
590 bank
->sectors
= NULL
;
593 size_t bank_size
= 0;
595 if (is_mflash_bank(bank
))
596 bank_size
= flash_sz_bytes
;
597 else if (is_wflash_bank(bank
))
598 bank_size
= MEM_WFLASH_SIZE
;
599 else if (is_sflash_bank(bank
)) {
600 for (size_t i
= 0; i
< SFLASH_NUM_REGIONS
; i
++) {
601 if (safe_sflash_regions
[i
].addr
== bank
->base
) {
602 bank_size
= safe_sflash_regions
[i
].size
;
608 if (bank_size
== 0) {
609 LOG_ERROR("Invalid Flash Bank base address in config file");
610 return ERROR_FLASH_BANK_INVALID
;
613 unsigned int num_sectors
= bank_size
/ row_sz
;
614 bank
->size
= bank_size
;
615 bank
->chip_width
= 4;
617 bank
->erased_value
= 0;
618 bank
->default_padded_value
= 0;
620 bank
->num_sectors
= num_sectors
;
621 bank
->sectors
= calloc(num_sectors
, sizeof(struct flash_sector
));
622 for (unsigned int i
= 0; i
< num_sectors
; i
++) {
623 bank
->sectors
[i
].size
= row_sz
;
624 bank
->sectors
[i
].offset
= i
* row_sz
;
625 bank
->sectors
[i
].is_erased
= -1;
626 bank
->sectors
[i
].is_protected
= -1;
629 psoc6_info
->is_probed
= true;
630 psoc6_info
->main_flash_sz
= flash_sz_bytes
;
631 psoc6_info
->row_sz
= row_sz
;
636 /** ***********************************************************************************************
637 * @brief Probes target device only if it hasn't been probed yet
638 * @param bank current flash bank
639 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
640 *************************************************************************************************/
641 static int psoc6_auto_probe(struct flash_bank
*bank
)
643 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
646 if (psoc6_info
->is_probed
)
649 hr
= psoc6_probe(bank
);
654 /** ***********************************************************************************************
655 * @brief Erases single sector (256k) on target device
656 * @param bank current flash bank
657 * @param wa working area for SROM API parameters
658 * @param addr starting address of the sector
659 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
660 *************************************************************************************************/
661 static int psoc6_erase_sector(struct flash_bank
*bank
, struct working_area
*wa
, uint32_t addr
)
663 struct target
*target
= bank
->target
;
665 LOG_DEBUG("Erasing SECTOR @%08X", addr
);
667 int hr
= target_write_u32(target
, wa
->address
, SROMAPI_ERASESECTOR_REQ
);
671 hr
= target_write_u32(target
, wa
->address
+ 0x04, addr
);
676 hr
= call_sromapi(target
, SROMAPI_ERASESECTOR_REQ
, wa
->address
, &data_out
);
678 LOG_ERROR("SECTOR @%08X not erased!", addr
);
683 /** ***********************************************************************************************
684 * @brief Erases single row (512b) on target device
685 * @param bank current flash bank
686 * @param wa working area for SROM API parameters
687 * @param addr starting address of the flash row
688 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
689 *************************************************************************************************/
690 static int psoc6_erase_row(struct flash_bank
*bank
, struct working_area
*wa
, uint32_t addr
)
692 struct target
*target
= bank
->target
;
694 LOG_DEBUG("Erasing ROW @%08X", addr
);
696 int hr
= target_write_u32(target
, wa
->address
, SROMAPI_ERASEROW_REQ
);
700 hr
= target_write_u32(target
, wa
->address
+ 0x04, addr
);
705 hr
= call_sromapi(target
, SROMAPI_ERASEROW_REQ
, wa
->address
, &data_out
);
707 LOG_ERROR("ROW @%08X not erased!", addr
);
712 /** ***********************************************************************************************
713 * @brief Performs Erase operation. Function will try to use biggest erase block possible to
714 * speedup the operation.
716 * @param bank current flash bank
717 * @param first first sector to erase
718 * @param last last sector to erase
719 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
720 *************************************************************************************************/
721 static int psoc6_erase(struct flash_bank
*bank
, unsigned int first
,
724 struct target
*target
= bank
->target
;
725 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
726 const uint32_t sector_size
= is_wflash_bank(bank
) ? WFLASH_SECTOR_SIZE
: MFLASH_SECTOR_SIZE
;
729 struct working_area
*wa
;
731 if (is_sflash_bank(bank
)) {
732 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
736 hr
= sromalgo_prepare(target
);
740 hr
= target_alloc_working_area(target
, psoc6_info
->row_sz
+ 32, &wa
);
744 /* Number of rows in single sector */
745 const unsigned int rows_in_sector
= sector_size
/ psoc6_info
->row_sz
;
747 while (last
>= first
) {
748 /* Erase Sector if we are on sector boundary and erase size covers whole sector */
749 if ((first
% rows_in_sector
) == 0 &&
750 (last
- first
+ 1) >= rows_in_sector
) {
751 hr
= psoc6_erase_sector(bank
, wa
, bank
->base
+ first
* psoc6_info
->row_sz
);
755 for (unsigned int i
= first
; i
< first
+ rows_in_sector
; i
++)
756 bank
->sectors
[i
].is_erased
= 1;
758 first
+= rows_in_sector
;
760 /* Perform Row Erase otherwise */
761 hr
= psoc6_erase_row(bank
, wa
, bank
->base
+ first
* psoc6_info
->row_sz
);
765 bank
->sectors
[first
].is_erased
= 1;
771 target_free_working_area(target
, wa
);
773 sromalgo_release(target
);
777 /** ***********************************************************************************************
778 * @brief Programs single Flash Row
779 * @param bank current flash bank
780 * @param addr address of the flash row
781 * @param buffer pointer to the buffer with data
782 * @param is_sflash true if current flash bank belongs to Supervisory Flash
783 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
784 *************************************************************************************************/
785 static int psoc6_program_row(struct flash_bank
*bank
,
787 const uint8_t *buffer
,
790 struct target
*target
= bank
->target
;
791 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
792 struct working_area
*wa
;
793 const uint32_t sromapi_req
= is_sflash
? SROMAPI_WRITEROW_REQ
: SROMAPI_PROGRAMROW_REQ
;
797 LOG_DEBUG("Programming ROW @%08X", addr
);
799 hr
= target_alloc_working_area(target
, psoc6_info
->row_sz
+ 32, &wa
);
803 hr
= target_write_u32(target
, wa
->address
, sromapi_req
);
807 hr
= target_write_u32(target
,
813 hr
= target_write_u32(target
, wa
->address
+ 0x08, addr
);
817 hr
= target_write_u32(target
, wa
->address
+ 0x0C, wa
->address
+ 0x10);
821 hr
= target_write_buffer(target
, wa
->address
+ 0x10, psoc6_info
->row_sz
, buffer
);
825 hr
= call_sromapi(target
, sromapi_req
, wa
->address
, &data_out
);
828 target_free_working_area(target
, wa
);
834 /** ***********************************************************************************************
835 * @brief Performs Program operation
836 * @param bank current flash bank
837 * @param buffer pointer to the buffer with data
838 * @param offset starting offset in falsh bank
839 * @param count number of bytes in buffer
840 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
841 *************************************************************************************************/
842 static int psoc6_program(struct flash_bank
*bank
,
843 const uint8_t *buffer
,
847 struct target
*target
= bank
->target
;
848 struct psoc6_target_info
*psoc6_info
= bank
->driver_priv
;
849 const bool is_sflash
= is_sflash_bank(bank
);
852 uint8_t page_buf
[psoc6_info
->row_sz
];
854 hr
= sromalgo_prepare(target
);
859 uint32_t row_offset
= offset
% psoc6_info
->row_sz
;
860 uint32_t aligned_addr
= bank
->base
+ offset
- row_offset
;
861 uint32_t row_bytes
= MIN(psoc6_info
->row_sz
- row_offset
, count
);
863 memset(page_buf
, 0, sizeof(page_buf
));
864 memcpy(&page_buf
[row_offset
], buffer
, row_bytes
);
866 hr
= psoc6_program_row(bank
, aligned_addr
, page_buf
, is_sflash
);
867 if (hr
!= ERROR_OK
) {
868 LOG_ERROR("Failed to program Flash at address 0x%08X", aligned_addr
);
878 sromalgo_release(target
);
882 /** ***********************************************************************************************
883 * @brief Performs Mass Erase operation
884 * @param bank flash bank index to erase
885 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
886 *************************************************************************************************/
887 COMMAND_HANDLER(psoc6_handle_mass_erase_command
)
890 return ERROR_COMMAND_SYNTAX_ERROR
;
892 struct flash_bank
*bank
;
893 int hr
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
897 hr
= psoc6_erase(bank
, 0, bank
->num_sectors
- 1);
902 /** ***********************************************************************************************
903 * @brief Simulates broken Vector Catch
904 * Function will try to determine entry point of user application. If it succeeds it will set HW
905 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
906 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
907 * reset CM4 anyway, so using SYSRESETREQ is safe here.
908 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
910 * @param target current target
911 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
912 *************************************************************************************************/
913 int handle_reset_halt(struct target
*target
)
917 bool is_cm0
= (target
->coreid
== 0);
919 /* Halt target device */
920 if (target
->state
!= TARGET_HALTED
) {
921 hr
= target_halt(target
);
925 target_wait_state(target
, TARGET_HALTED
, IPC_TIMEOUT_MS
);
930 /* Read Vector Offset register */
932 const uint32_t vt_offset_reg
= is_cm0
? 0x402102B0 : 0x402102C0;
933 hr
= target_read_u32(target
, vt_offset_reg
, &vt_base
);
937 /* Invalid value means flash is empty */
938 vt_base
&= 0xFFFFFF00;
939 if ((vt_base
== 0) || (vt_base
== 0xFFFFFF00))
942 /* Read Reset Vector value*/
943 hr
= target_read_u32(target
, vt_base
+ 4, &reset_addr
);
947 /* Invalid value means flash is empty */
948 if ((reset_addr
== 0) || (reset_addr
== 0xFFFFFF00))
952 /* Set breakpoint at User Application entry point */
953 hr
= breakpoint_add(target
, reset_addr
, 2, BKPT_HARD
);
957 const struct armv7m_common
*cm
= target_to_armv7m(target
);
959 /* PSoC6 reboots immediatelly after issuing SYSRESETREQ / VECTRESET
960 * this disables SWD/JTAG pins momentarily and may break communication
961 * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */
963 /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
964 LOG_INFO("psoc6.cm0: bkpt @0x%08X, issuing SYSRESETREQ", reset_addr
);
965 mem_ap_write_atomic_u32(cm
->debug_ap
, NVIC_AIRCR
,
966 AIRCR_VECTKEY
| AIRCR_SYSRESETREQ
);
968 LOG_INFO("psoc6.cm4: bkpt @0x%08X, issuing VECTRESET", reset_addr
);
969 mem_ap_write_atomic_u32(cm
->debug_ap
, NVIC_AIRCR
,
970 AIRCR_VECTKEY
| AIRCR_VECTRESET
);
973 /* Wait 100ms for bootcode and reinitialize DAP */
975 dap_dp_init(cm
->debug_ap
->dap
);
977 target_wait_state(target
, TARGET_HALTED
, IPC_TIMEOUT_MS
);
979 /* Remove the break point */
980 breakpoint_remove(target
, reset_addr
);
985 /** ***********************************************************************************************
986 * @brief Simulates broken Vector Catch
987 * Function will try to determine entry point of user application. If it succeeds it will set HW
988 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
989 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
990 * reset CM4 anyway, so using SYSRESETREQ is safe here.
991 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
993 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
994 *************************************************************************************************/
995 COMMAND_HANDLER(psoc6_handle_reset_halt
)
998 return ERROR_COMMAND_SYNTAX_ERROR
;
1000 struct target
*target
= get_current_target(CMD_CTX
);
1001 return handle_reset_halt(target
);
1004 FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command
)
1006 struct psoc6_target_info
*psoc6_info
;
1010 hr
= ERROR_COMMAND_SYNTAX_ERROR
;
1012 psoc6_info
= calloc(1, sizeof(struct psoc6_target_info
));
1013 psoc6_info
->is_probed
= false;
1014 bank
->driver_priv
= psoc6_info
;
1019 static const struct command_registration psoc6_exec_command_handlers
[] = {
1021 .name
= "mass_erase",
1022 .handler
= psoc6_handle_mass_erase_command
,
1023 .mode
= COMMAND_EXEC
,
1025 .help
= "Erases entire Main Flash",
1028 .name
= "reset_halt",
1029 .handler
= psoc6_handle_reset_halt
,
1030 .mode
= COMMAND_EXEC
,
1032 .help
= "Tries to simulate broken Vector Catch",
1034 COMMAND_REGISTRATION_DONE
1037 static const struct command_registration psoc6_command_handlers
[] = {
1040 .mode
= COMMAND_ANY
,
1041 .help
= "PSoC 6 flash command group",
1043 .chain
= psoc6_exec_command_handlers
,
1045 COMMAND_REGISTRATION_DONE
1048 const struct flash_driver psoc6_flash
= {
1050 .commands
= psoc6_command_handlers
,
1051 .flash_bank_command
= psoc6_flash_bank_command
,
1052 .erase
= psoc6_erase
,
1053 .protect
= psoc6_protect
,
1054 .write
= psoc6_program
,
1055 .read
= default_flash_read
,
1056 .probe
= psoc6_probe
,
1057 .auto_probe
= psoc6_auto_probe
,
1058 .erase_check
= default_flash_blank_check
,
1059 .protect_check
= psoc6_protect_check
,
1060 .info
= psoc6_get_info
,
1061 .free_driver_priv
= default_flash_free_driver_priv
,
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)