flash/nor/rp2040: fix flash erase timeout
[openocd.git] / src / flash / nor / psoc6.c
blobb7ba1027ed49e45760ebfcc1726df4d66254ae43
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * *
5 * Copyright (C) 2018 by Bohdan Tymkiv *
6 * bohdan.tymkiv@cypress.com bohdan200@gmail.com *
7 ***************************************************************************/
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
13 #include <time.h>
15 #include "imp.h"
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
58 #define IPC_ID 2u
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 {
77 uint32_t silicon_id;
78 uint8_t protection;
79 uint32_t main_flash_sz;
80 uint32_t row_sz;
81 bool is_probed;
84 struct timeout {
85 int64_t start_time;
86 long timeout_ms;
89 struct row_region {
90 uint32_t addr;
91 size_t size;
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)
137 int hr;
139 /* Initialize Vector Table Offset register (in case FW modified it) */
140 hr = target_write_u32(target, 0xE000ED08, 0x00000000);
141 if (hr != ERROR_OK)
142 return hr;
144 /* Allocate Working Area for Stack and Flash algorithm */
145 hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
146 if (hr != ERROR_OK)
147 return hr;
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(&reg_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);
158 if (hr != ERROR_OK)
159 goto destroy_rp_free_wa;
161 hr = target_start_algorithm(target, 0, NULL, 1, &reg_params, g_stack_area->address,
162 0, &g_armv7m_info);
163 if (hr != ERROR_OK)
164 goto destroy_rp_free_wa;
166 destroy_reg_param(&reg_params);
168 return hr;
170 destroy_rp_free_wa:
171 /* Something went wrong, do some cleanup */
172 destroy_reg_param(&reg_params);
174 target_free_working_area(target, g_stack_area);
175 g_stack_area = NULL;
177 return hr;
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)
189 int hr = ERROR_OK;
191 if (g_stack_area) {
192 /* Stop flash algorithm if it is running */
193 if (target->running_alg) {
194 hr = target_halt(target);
195 if (hr != ERROR_OK)
196 goto exit_free_wa;
198 hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
199 IPC_TIMEOUT_MS, &g_armv7m_info);
200 if (hr != ERROR_OK)
201 goto exit_free_wa;
204 exit_free_wa:
205 /* Free Stack/Flash algorithm working area */
206 target_free_working_area(target, g_stack_area);
207 g_stack_area = NULL;
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
216 * in expected state
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)
225 int hr;
226 uint32_t reg_val;
228 struct timeout to;
229 timeout_init(&to, IPC_TIMEOUT_MS);
231 while (!timeout_expired(&to)) {
232 /* Process any server requests */
233 keep_alive();
235 /* Read IPC Lock status */
236 hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), &reg_val);
237 if (hr != ERROR_OK) {
238 LOG_ERROR("Unable to read IPC Lock Status register");
239 return hr;
242 bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
244 if (lock_expected == is_locked)
245 return ERROR_OK;
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)
269 int hr = ERROR_OK;
270 bool is_acquired = false;
271 uint32_t reg_val;
273 struct timeout to;
274 timeout_init(&to, IPC_TIMEOUT_MS);
276 while (!timeout_expired(&to)) {
277 keep_alive();
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");
282 return hr;
285 /* Check if data is written on first step */
286 hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), &reg_val);
287 if (hr != ERROR_OK) {
288 LOG_ERROR("Unable to read IPC Acquire register");
289 return hr;
292 is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
293 if (is_acquired) {
294 /* If IPC structure is acquired, the lock status should be set */
295 hr = ipc_poll_lock_stat(target, ipc_id, true);
296 break;
300 if (!is_acquired)
301 LOG_ERROR("Timeout acquiring IPC structure");
303 return hr;
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,
318 uint32_t *data_out)
320 int hr;
322 bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
324 hr = ipc_acquire(target, IPC_ID);
325 if (hr != ERROR_OK)
326 return hr;
328 if (is_data_in_ram)
329 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area);
330 else
331 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params);
333 if (hr != ERROR_OK)
334 return hr;
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));
338 if (hr != ERROR_OK)
339 return hr;
341 hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
342 if (hr != ERROR_OK)
343 return hr;
345 /* Poll lock status */
346 hr = ipc_poll_lock_stat(target, IPC_ID, false);
347 if (hr != ERROR_OK)
348 return hr;
350 /* Poll Data byte */
351 if (is_data_in_ram)
352 hr = target_read_u32(target, working_area, data_out);
353 else
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");
358 return hr;
361 bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS;
362 if (!is_success) {
363 LOG_ERROR("SROM API execution failed. Status: 0x%08" PRIX32, *data_out);
364 return ERROR_TARGET_FAILURE;
367 return ERROR_OK;
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)
379 int hr;
380 uint32_t family_rev, siid_prot;
382 hr = sromalgo_prepare(target);
383 if (hr != ERROR_OK)
384 goto exit;
386 /* Read FamilyID and Revision */
387 hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev);
388 if (hr != ERROR_OK)
389 goto exit;
391 /* Read SiliconID and Protection */
392 hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
393 if (hr != ERROR_OK)
394 goto exit;
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;
402 exit:
403 sromalgo_release(target);
404 return ERROR_OK;
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)
414 int is_protected;
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);
418 if (hr != ERROR_OK)
419 return hr;
421 switch (psoc6_info->protection) {
422 case PROTECTION_VIRGIN:
423 case PROTECTION_NORMAL:
424 is_protected = 0;
425 break;
427 case PROTECTION_UNKNOWN:
428 case PROTECTION_SECURE:
429 case PROTECTION_DEAD:
430 default:
431 is_protected = 1;
432 break;
435 for (unsigned int i = 0; i < bank->num_sectors; i++)
436 bank->sectors[i].is_protected = is_protected;
438 return ERROR_OK;
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,
446 unsigned int last)
448 (void)bank;
449 (void)set;
450 (void)first;
451 (void)last;
453 LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
454 return ERROR_OK;
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:
466 return "VIRGIN";
467 case PROTECTION_NORMAL:
468 return "NORMAL";
469 case PROTECTION_SECURE:
470 return "SECURE";
471 case PROTECTION_DEAD:
472 return "DEAD";
473 case PROTECTION_UNKNOWN:
474 default:
475 return "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)
490 return ERROR_FAIL;
492 int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
493 if (hr != ERROR_OK)
494 return hr;
496 command_print_sameline(cmd,
497 "PSoC6 Silicon ID: 0x%08" PRIX32 "\n"
498 "Protection: %s\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);
505 return ERROR_OK;
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)
517 return true;
520 return false;
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;
556 int hr = ERROR_OK;
558 /* Retrieve data from SPCIF_GEOMETRY */
559 uint32_t geom;
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;
569 free(bank->sectors);
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;
582 break;
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;
611 return hr;
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;
622 int hr;
624 if (psoc6_info->is_probed)
625 hr = ERROR_OK;
626 else
627 hr = psoc6_probe(bank);
629 return hr;
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);
646 if (hr != ERROR_OK)
647 return hr;
649 hr = target_write_u32(target, wa->address + 0x04, addr);
650 if (hr != ERROR_OK)
651 return hr;
653 uint32_t data_out;
654 hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out);
655 if (hr != ERROR_OK)
656 LOG_ERROR("SECTOR @%08" PRIX32 " not erased!", addr);
658 return hr;
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);
675 if (hr != ERROR_OK)
676 return hr;
678 hr = target_write_u32(target, wa->address + 0x04, addr);
679 if (hr != ERROR_OK)
680 return hr;
682 uint32_t data_out;
683 hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out);
684 if (hr != ERROR_OK)
685 LOG_ERROR("ROW @%08" PRIX32 " not erased!", addr);
687 return hr;
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,
700 unsigned int last)
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;
706 int hr;
707 struct working_area *wa;
709 if (is_sflash_bank(bank)) {
710 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
711 return ERROR_OK;
714 hr = sromalgo_prepare(target);
715 if (hr != ERROR_OK)
716 goto exit;
718 hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
719 if (hr != ERROR_OK)
720 goto exit;
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);
730 if (hr != ERROR_OK)
731 goto exit_free_wa;
733 first += rows_in_sector;
734 } else {
735 /* Perform Row Erase otherwise */
736 hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz);
737 if (hr != ERROR_OK)
738 goto exit_free_wa;
740 first += 1;
744 exit_free_wa:
745 target_free_working_area(target, wa);
746 exit:
747 sromalgo_release(target);
748 return hr;
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,
760 uint32_t addr,
761 const uint8_t *buffer,
762 bool is_sflash)
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;
768 uint32_t data_out;
769 int hr = ERROR_OK;
771 LOG_DEBUG("Programming ROW @%08" PRIX32, addr);
773 hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
774 if (hr != ERROR_OK)
775 goto exit;
777 hr = target_write_u32(target, wa->address, sromapi_req);
778 if (hr != ERROR_OK)
779 goto exit_free_wa;
781 hr = target_write_u32(target,
782 wa->address + 0x04,
783 0x106);
784 if (hr != ERROR_OK)
785 goto exit_free_wa;
787 hr = target_write_u32(target, wa->address + 0x08, addr);
788 if (hr != ERROR_OK)
789 goto exit_free_wa;
791 hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
792 if (hr != ERROR_OK)
793 goto exit_free_wa;
795 hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer);
796 if (hr != ERROR_OK)
797 goto exit_free_wa;
799 hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
801 exit_free_wa:
802 target_free_working_area(target, wa);
804 exit:
805 return hr;
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,
818 uint32_t offset,
819 uint32_t count)
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);
824 int hr;
826 uint8_t page_buf[psoc6_info->row_sz];
828 hr = sromalgo_prepare(target);
829 if (hr != ERROR_OK)
830 goto exit;
832 while (count) {
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);
843 goto exit;
846 buffer += row_bytes;
847 offset += row_bytes;
848 count -= row_bytes;
851 exit:
852 sromalgo_release(target);
853 return hr;
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)
862 if (CMD_ARGC != 1)
863 return ERROR_COMMAND_SYNTAX_ERROR;
865 struct flash_bank *bank;
866 int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
867 if (hr != ERROR_OK)
868 return hr;
870 hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
872 return hr;
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)
888 int hr;
889 uint32_t reset_addr;
890 bool is_cm0 = (target->coreid == 0);
892 /* Halt target device */
893 if (target->state != TARGET_HALTED) {
894 hr = target_halt(target);
895 if (hr != ERROR_OK)
896 return hr;
898 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
899 if (hr != ERROR_OK)
900 return hr;
903 /* Read Vector Offset register */
904 uint32_t vt_base;
905 const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
906 hr = target_read_u32(target, vt_offset_reg, &vt_base);
907 if (hr != ERROR_OK)
908 return ERROR_OK;
910 /* Invalid value means flash is empty */
911 vt_base &= 0xFFFFFF00;
912 if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
913 return ERROR_OK;
915 /* Read Reset Vector value*/
916 hr = target_read_u32(target, vt_base + 4, &reset_addr);
917 if (hr != ERROR_OK)
918 return hr;
920 /* Invalid value means flash is empty */
921 if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
922 return ERROR_OK;
925 /* Set breakpoint at User Application entry point */
926 hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD);
927 if (hr != ERROR_OK)
928 return hr;
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 */
935 if (is_cm0) {
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);
940 } else {
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 */
947 usleep(100000);
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);
955 return ERROR_OK;
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)
970 if (CMD_ARGC)
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;
980 int hr = ERROR_OK;
982 if (CMD_ARGC < 6)
983 hr = ERROR_COMMAND_SYNTAX_ERROR;
984 else {
985 psoc6_info = calloc(1, sizeof(struct psoc6_target_info));
986 psoc6_info->is_probed = false;
987 bank->driver_priv = psoc6_info;
989 return hr;
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,
997 .usage = "bank",
998 .help = "Erases entire Main Flash",
1001 .name = "reset_halt",
1002 .handler = psoc6_handle_reset_halt,
1003 .mode = COMMAND_EXEC,
1004 .usage = "",
1005 .help = "Tries to simulate broken Vector Catch",
1007 COMMAND_REGISTRATION_DONE
1010 static const struct command_registration psoc6_command_handlers[] = {
1012 .name = "psoc6",
1013 .mode = COMMAND_ANY,
1014 .help = "PSoC 6 flash command group",
1015 .usage = "",
1016 .chain = psoc6_exec_command_handlers,
1018 COMMAND_REGISTRATION_DONE
1021 const struct flash_driver psoc6_flash = {
1022 .name = "psoc6",
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,