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 /* Allocate Working Area for Stack and Flash algorithm */
155 hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
159 g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
160 g_armv7m_info.core_mode = ARM_MODE_THREAD;
162 struct reg_param reg_params;
163 init_reg_param(®_params, "sp", 32, PARAM_OUT);
164 buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size);
166 /* Write basic infinite loop algorithm to target RAM */
167 hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7);
169 goto destroy_rp_free_wa;
171 hr = target_start_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address,
174 goto destroy_rp_free_wa;
176 destroy_reg_param(®_params);
181 /* Something went wrong, do some cleanup */
182 destroy_reg_param(®_params);
185 target_free_working_area(target, g_stack_area);
192 /** ***********************************************************************************************
193 * @brief Stops running flash algorithm and releases associated resources.
194 * This function is also used for cleanup in case of errors so g_stack_area may be NULL.
195 * These cases have to be handled gracefully.
197 * @param target current target
198 *************************************************************************************************/
199 static void sromalgo_release(struct target *target)
204 /* Stop flash algorithm if it is running */
205 if (target->running_alg) {
206 hr = target_halt(target);
210 hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
211 IPC_TIMEOUT_MS, &g_armv7m_info);
217 /* Free Stack/Flash algorithm working area */
218 target_free_working_area(target, g_stack_area);
223 /** ***********************************************************************************************
224 * @brief Waits for expected IPC lock status. PSoC6 uses IPC structures for inter-core
225 * communication. Same IPCs are used to invoke SROM API. IPC structure must be locked prior to
226 * invoking any SROM API. This ensures nothing else in the system will use same IPC thus corrupting
227 * our data. Locking is performed by ipc_acquire(), this function ensures that IPC is actually
230 * @param target current target
231 * @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access
232 * @param lock_expected expected lock status
233 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
234 *************************************************************************************************/
235 static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected)
241 timeout_init(&to, IPC_TIMEOUT_MS);
243 while (!timeout_expired(&to)) {
244 /* Process any server requests */
247 /* Read IPC Lock status */
248 hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), ®_val);
249 if (hr != ERROR_OK) {
250 LOG_ERROR("Unable to read IPC Lock Status register");
254 bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
256 if (lock_expected == is_locked)
260 if (target->coreid) {
261 LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. "
262 "Please perform all Flash-related operations via CM0+ target on dual-core devices.");
265 LOG_ERROR("Timeout polling IPC Lock Status");
266 return ERROR_TARGET_TIMEOUT;
269 /** ***********************************************************************************************
270 * @brief Acquires IPC structure. PSoC6 uses IPC structures for inter-core communication.
271 * Same IPCs are used to invoke SROM API. IPC structure must be locked prior to invoking any SROM API.
272 * This ensures nothing else in the system will use same IPC thus corrupting our data.
273 * This function locks the IPC.
275 * @param target current target
276 * @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP access
277 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
278 *************************************************************************************************/
279 static int ipc_acquire(struct target *target, char ipc_id)
282 bool is_acquired = false;
286 timeout_init(&to, IPC_TIMEOUT_MS);
288 while (!timeout_expired(&to)) {
291 hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), IPC_ACQUIRE_SUCCESS_MSK);
292 if (hr != ERROR_OK) {
293 LOG_ERROR("Unable to write to IPC Acquire register");
297 /* Check if data is written on first step */
298 hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), ®_val);
299 if (hr != ERROR_OK) {
300 LOG_ERROR("Unable to read IPC Acquire register");
304 is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
306 /* If IPC structure is acquired, the lock status should be set */
307 hr = ipc_poll_lock_stat(target, ipc_id, true);
313 LOG_ERROR("Timeout acquiring IPC structure");
318 /** ***********************************************************************************************
319 * @brief Invokes SROM API functions which are responsible for Flash operations
321 * @param target current target
322 * @param req_and_params request id of the function to invoke
323 * @param working_area address of memory buffer in target's memory space for SROM API parameters
324 * @param data_out pointer to variable which will be populated with execution status
325 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
326 *************************************************************************************************/
327 static int call_sromapi(struct target *target,
328 uint32_t req_and_params,
329 uint32_t working_area,
334 bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
336 hr = ipc_acquire(target, IPC_ID);
341 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area);
343 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params);
348 /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */
349 hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + IPC_ID));
353 hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
357 /* Poll lock status */
358 hr = ipc_poll_lock_stat(target, IPC_ID, false);
364 hr = target_read_u32(target, working_area, data_out);
366 hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out);
368 if (hr != ERROR_OK) {
369 LOG_ERROR("Error reading SROM API Status location");
373 bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS;
375 LOG_ERROR("SROM API execution failed. Status: 0x%08" PRIX32, *data_out);
376 return ERROR_TARGET_FAILURE;
382 /** ***********************************************************************************************
383 * @brief Retrieves SiliconID and Protection status of the target device
384 * @param target current target
385 * @param si_id pointer to variable, will be populated with SiliconID
386 * @param protection pointer to variable, will be populated with protection status
387 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
388 *************************************************************************************************/
389 static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection)
392 uint32_t family_rev, siid_prot;
394 hr = sromalgo_prepare(target);
398 /* Read FamilyID and Revision */
399 hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev);
403 /* Read SiliconID and Protection */
404 hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
408 *si_id = (siid_prot & 0x0000FFFF) << 16;
409 *si_id |= (family_rev & 0x00FF0000) >> 8;
410 *si_id |= (family_rev & 0x000000FF) >> 0;
412 *protection = (siid_prot & 0x000F0000) >> 0x10;
415 sromalgo_release(target);
419 /** ***********************************************************************************************
420 * @brief Translates Protection status to openocd-friendly boolean value
421 * @param bank current flash bank
422 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
423 *************************************************************************************************/
424 static int psoc6_protect_check(struct flash_bank *bank)
428 struct psoc6_target_info *psoc6_info = bank->driver_priv;
429 int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
433 switch (psoc6_info->protection) {
434 case PROTECTION_VIRGIN:
435 case PROTECTION_NORMAL:
439 case PROTECTION_UNKNOWN:
440 case PROTECTION_SECURE:
441 case PROTECTION_DEAD:
447 for (unsigned int i = 0; i < bank->num_sectors; i++)
448 bank->sectors[i].is_protected = is_protected;
453 /** ***********************************************************************************************
454 * @brief Dummy function, Life Cycle transition is not currently supported
455 * @return ERROR_OK always
456 *************************************************************************************************/
457 static int psoc6_protect(struct flash_bank *bank, int set, unsigned int first,
465 LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
469 /** ***********************************************************************************************
470 * @brief Translates Protection status to string
471 * @param protection protection value
472 * @return pointer to const string describing protection status
473 *************************************************************************************************/
474 static const char *protection_to_str(uint8_t protection)
476 switch (protection) {
477 case PROTECTION_VIRGIN:
479 case PROTECTION_NORMAL:
481 case PROTECTION_SECURE:
483 case PROTECTION_DEAD:
485 case PROTECTION_UNKNOWN:
491 /** ***********************************************************************************************
492 * @brief psoc6_get_info Displays human-readable information about acquired device
493 * @param bank current flash bank
494 * @param buf pointer to buffer for human-readable text
495 * @param buf_size size of the buffer
496 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
497 *************************************************************************************************/
498 static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size)
500 struct psoc6_target_info *psoc6_info = bank->driver_priv;
502 if (psoc6_info->is_probed == false)
505 int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
509 snprintf(buf, buf_size,
510 "PSoC6 Silicon ID: 0x%08" PRIX32 "\n"
512 "Main Flash size: %" PRIu32 " kB\n"
513 "Work Flash size: 32 kB\n",
514 psoc6_info->silicon_id,
515 protection_to_str(psoc6_info->protection),
516 psoc6_info->main_flash_sz / 1024);
521 /** ***********************************************************************************************
522 * @brief Checks if given flash bank belongs to Supervisory Flash
523 * @param bank current flash bank
524 * @return true if flash bank belongs to Supervisory Flash
525 *************************************************************************************************/
526 static bool is_sflash_bank(struct flash_bank *bank)
528 for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
529 if (bank->base == safe_sflash_regions[i].addr)
536 /** ***********************************************************************************************
537 * @brief Checks if given flash bank belongs to Work Flash
538 * @param bank current flash bank
539 * @return true if flash bank belongs to Work Flash
540 *************************************************************************************************/
541 static inline bool is_wflash_bank(struct flash_bank *bank)
543 return (bank->base == MEM_BASE_WFLASH);
546 /** ***********************************************************************************************
547 * @brief Checks if given flash bank belongs to Main Flash
548 * @param bank current flash bank
549 * @return true if flash bank belongs to Main Flash
550 *************************************************************************************************/
551 static inline bool is_mflash_bank(struct flash_bank *bank)
553 return (bank->base == MEM_BASE_MFLASH);
556 /** ***********************************************************************************************
557 * @brief Probes the device and populates related data structures with target flash geometry data.
558 * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a
559 * running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers)
561 * @param bank current flash bank
562 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
563 *************************************************************************************************/
564 static int psoc6_probe(struct flash_bank *bank)
566 struct target *target = bank->target;
567 struct psoc6_target_info *psoc6_info = bank->driver_priv;
571 /* Retrieve data from SPCIF_GEOMETRY */
573 target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom);
574 uint32_t row_sz_lg2 = (geom & 0xF0) >> 4;
575 uint32_t row_sz = (0x01 << row_sz_lg2);
576 uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8);
577 uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24);
579 /* Calculate size of Main Flash*/
580 uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz;
583 bank->sectors = NULL;
585 size_t bank_size = 0;
587 if (is_mflash_bank(bank))
588 bank_size = flash_sz_bytes;
589 else if (is_wflash_bank(bank))
590 bank_size = MEM_WFLASH_SIZE;
591 else if (is_sflash_bank(bank)) {
592 for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
593 if (safe_sflash_regions[i].addr == bank->base) {
594 bank_size = safe_sflash_regions[i].size;
600 if (bank_size == 0) {
601 LOG_ERROR("Invalid Flash Bank base address in config file");
602 return ERROR_FLASH_BANK_INVALID;
605 unsigned int num_sectors = bank_size / row_sz;
606 bank->size = bank_size;
607 bank->chip_width = 4;
609 bank->erased_value = 0;
610 bank->default_padded_value = 0;
612 bank->num_sectors = num_sectors;
613 bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
614 for (unsigned int i = 0; i < num_sectors; i++) {
615 bank->sectors[i].size = row_sz;
616 bank->sectors[i].offset = i * row_sz;
617 bank->sectors[i].is_erased = -1;
618 bank->sectors[i].is_protected = -1;
621 psoc6_info->is_probed = true;
622 psoc6_info->main_flash_sz = flash_sz_bytes;
623 psoc6_info->row_sz = row_sz;
628 /** ***********************************************************************************************
629 * @brief Probes target device only if it hasn't been probed yet
630 * @param bank current flash bank
631 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
632 *************************************************************************************************/
633 static int psoc6_auto_probe(struct flash_bank *bank)
635 struct psoc6_target_info *psoc6_info = bank->driver_priv;
638 if (psoc6_info->is_probed)
641 hr = psoc6_probe(bank);
646 /** ***********************************************************************************************
647 * @brief Erases single sector (256k) on target device
648 * @param bank current flash bank
649 * @param wa working area for SROM API parameters
650 * @param addr starting address of the sector
651 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
652 *************************************************************************************************/
653 static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
655 struct target *target = bank->target;
657 LOG_DEBUG("Erasing SECTOR @%08" PRIX32, addr);
659 int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ);
663 hr = target_write_u32(target, wa->address + 0x04, addr);
668 hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out);
670 LOG_ERROR("SECTOR @%08" PRIX32 " not erased!", addr);
675 /** ***********************************************************************************************
676 * @brief Erases single row (512b) on target device
677 * @param bank current flash bank
678 * @param wa working area for SROM API parameters
679 * @param addr starting address of the flash row
680 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
681 *************************************************************************************************/
682 static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
684 struct target *target = bank->target;
686 LOG_DEBUG("Erasing ROW @%08" PRIX32, addr);
688 int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ);
692 hr = target_write_u32(target, wa->address + 0x04, addr);
697 hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out);
699 LOG_ERROR("ROW @%08" PRIX32 " not erased!", addr);
704 /** ***********************************************************************************************
705 * @brief Performs Erase operation. Function will try to use biggest erase block possible to
706 * speedup the operation.
708 * @param bank current flash bank
709 * @param first first sector to erase
710 * @param last last sector to erase
711 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
712 *************************************************************************************************/
713 static int psoc6_erase(struct flash_bank *bank, unsigned int first,
716 struct target *target = bank->target;
717 struct psoc6_target_info *psoc6_info = bank->driver_priv;
718 const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE : MFLASH_SECTOR_SIZE;
721 struct working_area *wa;
723 if (is_sflash_bank(bank)) {
724 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
728 hr = sromalgo_prepare(target);
732 hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
736 /* Number of rows in single sector */
737 const unsigned int rows_in_sector = sector_size / psoc6_info->row_sz;
739 while (last >= first) {
740 /* Erase Sector if we are on sector boundary and erase size covers whole sector */
741 if ((first % rows_in_sector) == 0 &&
742 (last - first + 1) >= rows_in_sector) {
743 hr = psoc6_erase_sector(bank, wa, bank->base + first * psoc6_info->row_sz);
747 for (unsigned int i = first; i < first + rows_in_sector; i++)
748 bank->sectors[i].is_erased = 1;
750 first += rows_in_sector;
752 /* Perform Row Erase otherwise */
753 hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz);
757 bank->sectors[first].is_erased = 1;
763 target_free_working_area(target, wa);
765 sromalgo_release(target);
769 /** ***********************************************************************************************
770 * @brief Programs single Flash Row
771 * @param bank current flash bank
772 * @param addr address of the flash row
773 * @param buffer pointer to the buffer with data
774 * @param is_sflash true if current flash bank belongs to Supervisory Flash
775 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
776 *************************************************************************************************/
777 static int psoc6_program_row(struct flash_bank *bank,
779 const uint8_t *buffer,
782 struct target *target = bank->target;
783 struct psoc6_target_info *psoc6_info = bank->driver_priv;
784 struct working_area *wa;
785 const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : SROMAPI_PROGRAMROW_REQ;
789 LOG_DEBUG("Programming ROW @%08" PRIX32, addr);
791 hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
795 hr = target_write_u32(target, wa->address, sromapi_req);
799 hr = target_write_u32(target,
805 hr = target_write_u32(target, wa->address + 0x08, addr);
809 hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
813 hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer);
817 hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
820 target_free_working_area(target, wa);
826 /** ***********************************************************************************************
827 * @brief Performs Program operation
828 * @param bank current flash bank
829 * @param buffer pointer to the buffer with data
830 * @param offset starting offset in flash bank
831 * @param count number of bytes in buffer
832 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
833 *************************************************************************************************/
834 static int psoc6_program(struct flash_bank *bank,
835 const uint8_t *buffer,
839 struct target *target = bank->target;
840 struct psoc6_target_info *psoc6_info = bank->driver_priv;
841 const bool is_sflash = is_sflash_bank(bank);
844 uint8_t page_buf[psoc6_info->row_sz];
846 hr = sromalgo_prepare(target);
851 uint32_t row_offset = offset % psoc6_info->row_sz;
852 uint32_t aligned_addr = bank->base + offset - row_offset;
853 uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, count);
855 memset(page_buf, 0, sizeof(page_buf));
856 memcpy(&page_buf[row_offset], buffer, row_bytes);
858 hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash);
859 if (hr != ERROR_OK) {
860 LOG_ERROR("Failed to program Flash at address 0x%08" PRIX32, aligned_addr);
870 sromalgo_release(target);
874 /** ***********************************************************************************************
875 * @brief Performs Mass Erase operation
876 * @param bank flash bank index to erase
877 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
878 *************************************************************************************************/
879 COMMAND_HANDLER(psoc6_handle_mass_erase_command)
882 return ERROR_COMMAND_SYNTAX_ERROR;
884 struct flash_bank *bank;
885 int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
889 hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
894 /** ***********************************************************************************************
895 * @brief Simulates broken Vector Catch
896 * Function will try to determine entry point of user application. If it succeeds it will set HW
897 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
898 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
899 * reset CM4 anyway, so using SYSRESETREQ is safe here.
900 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
902 * @param target current target
903 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
904 *************************************************************************************************/
905 static int handle_reset_halt(struct target *target)
909 bool is_cm0 = (target->coreid == 0);
911 /* Halt target device */
912 if (target->state != TARGET_HALTED) {
913 hr = target_halt(target);
917 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
922 /* Read Vector Offset register */
924 const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
925 hr = target_read_u32(target, vt_offset_reg, &vt_base);
929 /* Invalid value means flash is empty */
930 vt_base &= 0xFFFFFF00;
931 if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
934 /* Read Reset Vector value*/
935 hr = target_read_u32(target, vt_base + 4, &reset_addr);
939 /* Invalid value means flash is empty */
940 if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
944 /* Set breakpoint at User Application entry point */
945 hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD);
949 const struct armv7m_common *cm = target_to_armv7m(target);
951 /* PSoC6 reboots immediately after issuing SYSRESETREQ / VECTRESET
952 * this disables SWD/JTAG pins momentarily and may break communication
953 * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */
955 /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
956 LOG_INFO("psoc6.cm0: bkpt @0x%08" PRIX32 ", issuing SYSRESETREQ", reset_addr);
957 mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
958 AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
960 LOG_INFO("psoc6.cm4: bkpt @0x%08" PRIX32 ", issuing VECTRESET", reset_addr);
961 mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
962 AIRCR_VECTKEY | AIRCR_VECTRESET);
965 /* Wait 100ms for bootcode and reinitialize DAP */
967 dap_dp_init(cm->debug_ap->dap);
969 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
971 /* Remove the break point */
972 breakpoint_remove(target, reset_addr);
977 /** ***********************************************************************************************
978 * @brief Simulates broken Vector Catch
979 * Function will try to determine entry point of user application. If it succeeds it will set HW
980 * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
981 * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
982 * reset CM4 anyway, so using SYSRESETREQ is safe here.
983 * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
985 * @return ERROR_OK in case of success, ERROR_XXX code otherwise
986 *************************************************************************************************/
987 COMMAND_HANDLER(psoc6_handle_reset_halt)
990 return ERROR_COMMAND_SYNTAX_ERROR;
992 struct target *target = get_current_target(CMD_CTX);
993 return handle_reset_halt(target);
996 FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
998 struct psoc6_target_info *psoc6_info;
1002 hr = ERROR_COMMAND_SYNTAX_ERROR;
1004 psoc6_info = calloc(1, sizeof(struct psoc6_target_info));
1005 psoc6_info->is_probed = false;
1006 bank->driver_priv = psoc6_info;
1011 static const struct command_registration psoc6_exec_command_handlers[] = {
1013 .name = "mass_erase",
1014 .handler = psoc6_handle_mass_erase_command,
1015 .mode = COMMAND_EXEC,
1017 .help = "Erases entire Main Flash",
1020 .name = "reset_halt",
1021 .handler = psoc6_handle_reset_halt,
1022 .mode = COMMAND_EXEC,
1024 .help = "Tries to simulate broken Vector Catch",
1026 COMMAND_REGISTRATION_DONE
1029 static const struct command_registration psoc6_command_handlers[] = {
1032 .mode = COMMAND_ANY,
1033 .help = "PSoC 6 flash command group",
1035 .chain = psoc6_exec_command_handlers,
1037 COMMAND_REGISTRATION_DONE
1040 const struct flash_driver psoc6_flash = {
1042 .commands = psoc6_command_handlers,
1043 .flash_bank_command = psoc6_flash_bank_command,
1044 .erase = psoc6_erase,
1045 .protect = psoc6_protect,
1046 .write = psoc6_program,
1047 .read = default_flash_read,
1048 .probe = psoc6_probe,
1049 .auto_probe = psoc6_auto_probe,
1050 .erase_check = default_flash_blank_check,
1051 .protect_check = psoc6_protect_check,
1052 .info = psoc6_get_info,
1053 .free_driver_priv = default_flash_free_driver_priv,