da07d84871532ae796306ad6c9670781eaf9f433
[fw/openocd] / src / flash / nor / psoc6.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *                                                                         *
5  *   Copyright (C) 2018 by Bohdan Tymkiv                                   *
6  *   bohdan.tymkiv@cypress.com bohdan200@gmail.com                         *
7  ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include <time.h>
14
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"
23
24 /**************************************************************************************************
25  * PSoC6 device definitions
26  *************************************************************************************************/
27 #define MFLASH_SECTOR_SIZE              (256u * 1024u)
28 #define WFLASH_SECTOR_SIZE              (32u * 1024u)
29
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
36
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
42
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)
50
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
57
58 #define IPC_ID                          2u
59 #define IPC_INTR_ID                     0u
60 #define IPC_TIMEOUT_MS                  1000
61
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
70
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
75
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;
82 };
83
84 struct timeout {
85         int64_t start_time;
86         long timeout_ms;
87 };
88
89 struct row_region {
90         uint32_t addr;
91         size_t size;
92 };
93
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 */
99 };
100
101 #define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
102
103 static struct working_area *g_stack_area;
104 static struct armv7m_algorithm g_armv7m_info;
105
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)
112 {
113         to->start_time = timeval_ms();
114         to->timeout_ms = timeout_ms;
115 }
116
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)
123 {
124         return (timeval_ms() - to->start_time) > to->timeout_ms;
125 }
126
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.
131  *
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)
136 {
137         int hr;
138
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;
143
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;
148
149         g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
150         g_armv7m_info.core_mode = ARM_MODE_THREAD;
151
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);
155
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;
160
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;
165
166         destroy_reg_param(&reg_params);
167
168         return hr;
169
170 destroy_rp_free_wa:
171         /* Something went wrong, do some cleanup */
172         destroy_reg_param(&reg_params);
173
174         target_free_working_area(target, g_stack_area);
175         g_stack_area = NULL;
176
177         return hr;
178 }
179
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.
184  *
185  * @param target current target
186  *************************************************************************************************/
187 static void sromalgo_release(struct target *target)
188 {
189         int hr = ERROR_OK;
190
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;
197
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;
202                 }
203
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;
208         }
209 }
210
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
217  *
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)
224 {
225         int hr;
226         uint32_t reg_val;
227
228         struct timeout to;
229         timeout_init(&to, IPC_TIMEOUT_MS);
230
231         while (!timeout_expired(&to)) {
232                 /* Process any server requests */
233                 keep_alive();
234
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;
240                 }
241
242                 bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
243
244                 if (lock_expected == is_locked)
245                         return ERROR_OK;
246         }
247
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.");
251         }
252
253         LOG_ERROR("Timeout polling IPC Lock Status");
254         return ERROR_TARGET_TIMEOUT;
255 }
256
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.
262  *
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)
268 {
269         int hr = ERROR_OK;
270         bool is_acquired = false;
271         uint32_t reg_val;
272
273         struct timeout to;
274         timeout_init(&to, IPC_TIMEOUT_MS);
275
276         while (!timeout_expired(&to)) {
277                 keep_alive();
278
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;
283                 }
284
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;
290                 }
291
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;
297                 }
298         }
299
300         if (!is_acquired)
301                 LOG_ERROR("Timeout acquiring IPC structure");
302
303         return hr;
304 }
305
306 /** ***********************************************************************************************
307  * @brief Invokes SROM API functions which are responsible for Flash operations
308  *
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)
319 {
320         int hr;
321
322         bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
323
324         hr = ipc_acquire(target, IPC_ID);
325         if (hr != ERROR_OK)
326                 return hr;
327
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);
332
333         if (hr != ERROR_OK)
334                 return hr;
335
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;
340
341         hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
342         if (hr != ERROR_OK)
343                 return hr;
344
345         /* Poll lock status */
346         hr = ipc_poll_lock_stat(target, IPC_ID, false);
347         if (hr != ERROR_OK)
348                 return hr;
349
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);
355
356         if (hr != ERROR_OK) {
357                 LOG_ERROR("Error reading SROM API Status location");
358                 return hr;
359         }
360
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;
365         }
366
367         return ERROR_OK;
368 }
369
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)
378 {
379         int hr;
380         uint32_t family_rev, siid_prot;
381
382         hr = sromalgo_prepare(target);
383         if (hr != ERROR_OK)
384                 goto exit;
385
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;
390
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;
395
396         *si_id  = (siid_prot & 0x0000FFFF) << 16;
397         *si_id |= (family_rev & 0x00FF0000) >> 8;
398         *si_id |= (family_rev & 0x000000FF) >> 0;
399
400         *protection = (siid_prot & 0x000F0000) >> 0x10;
401
402 exit:
403         sromalgo_release(target);
404         return ERROR_OK;
405 }
406
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)
413 {
414         int is_protected;
415
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;
420
421         switch (psoc6_info->protection) {
422                 case PROTECTION_VIRGIN:
423                 case PROTECTION_NORMAL:
424                         is_protected = 0;
425                         break;
426
427                 case PROTECTION_UNKNOWN:
428                 case PROTECTION_SECURE:
429                 case PROTECTION_DEAD:
430                 default:
431                         is_protected = 1;
432                         break;
433         }
434
435         for (unsigned int i = 0; i < bank->num_sectors; i++)
436                 bank->sectors[i].is_protected = is_protected;
437
438         return ERROR_OK;
439 }
440
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)
447 {
448         (void)bank;
449         (void)set;
450         (void)first;
451         (void)last;
452
453         LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
454         return ERROR_OK;
455 }
456
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)
463 {
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";
476         }
477 }
478
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)
486 {
487         struct psoc6_target_info *psoc6_info = bank->driver_priv;
488
489         if (psoc6_info->is_probed == false)
490                 return ERROR_FAIL;
491
492         int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
493         if (hr != ERROR_OK)
494                 return hr;
495
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);
504
505         return ERROR_OK;
506 }
507
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)
514 {
515         for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
516                 if (bank->base == safe_sflash_regions[i].addr)
517                         return true;
518         }
519
520         return false;
521 }
522
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)
529 {
530         return (bank->base == MEM_BASE_WFLASH);
531 }
532
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)
539 {
540         return (bank->base == MEM_BASE_MFLASH);
541 }
542
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)
547  *
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)
552 {
553         struct target *target = bank->target;
554         struct psoc6_target_info *psoc6_info = bank->driver_priv;
555
556         int hr = ERROR_OK;
557
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);
565
566         /* Calculate size of Main Flash*/
567         uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz;
568
569         free(bank->sectors);
570         bank->sectors = NULL;
571
572         size_t bank_size = 0;
573
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;
583                         }
584                 }
585         }
586
587         if (bank_size == 0) {
588                 LOG_ERROR("Invalid Flash Bank base address in config file");
589                 return ERROR_FLASH_BANK_INVALID;
590         }
591
592         unsigned int num_sectors = bank_size / row_sz;
593         bank->size = bank_size;
594
595         bank->erased_value = 0;
596         bank->default_padded_value = 0;
597
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;
605         }
606
607         psoc6_info->is_probed = true;
608         psoc6_info->main_flash_sz = flash_sz_bytes;
609         psoc6_info->row_sz = row_sz;
610
611         return hr;
612 }
613
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)
620 {
621         struct psoc6_target_info *psoc6_info = bank->driver_priv;
622         int hr;
623
624         if (psoc6_info->is_probed)
625                 hr = ERROR_OK;
626         else
627                 hr = psoc6_probe(bank);
628
629         return hr;
630 }
631
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)
640 {
641         struct target *target = bank->target;
642
643         LOG_DEBUG("Erasing SECTOR @%08" PRIX32, addr);
644
645         int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ);
646         if (hr != ERROR_OK)
647                 return hr;
648
649         hr = target_write_u32(target, wa->address + 0x04, addr);
650         if (hr != ERROR_OK)
651                 return hr;
652
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);
657
658         return hr;
659 }
660
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)
669 {
670         struct target *target = bank->target;
671
672         LOG_DEBUG("Erasing ROW @%08" PRIX32, addr);
673
674         int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ);
675         if (hr != ERROR_OK)
676                 return hr;
677
678         hr = target_write_u32(target, wa->address + 0x04, addr);
679         if (hr != ERROR_OK)
680                 return hr;
681
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);
686
687         return hr;
688 }
689
690 /** ***********************************************************************************************
691  * @brief Performs Erase operation. Function will try to use biggest erase block possible to
692  * speedup the operation.
693  *
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)
701 {
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;
705
706         int hr;
707         struct working_area *wa;
708
709         if (is_sflash_bank(bank)) {
710                 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
711                 return ERROR_OK;
712         }
713
714         hr = sromalgo_prepare(target);
715         if (hr != ERROR_OK)
716                 goto exit;
717
718         hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
719         if (hr != ERROR_OK)
720                 goto exit;
721
722         /* Number of rows in single sector */
723         const unsigned int rows_in_sector = sector_size / psoc6_info->row_sz;
724
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;
732
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;
739
740                         first += 1;
741                 }
742         }
743
744 exit_free_wa:
745         target_free_working_area(target, wa);
746 exit:
747         sromalgo_release(target);
748         return hr;
749 }
750
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)
763 {
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;
770
771         LOG_DEBUG("Programming ROW @%08" PRIX32, addr);
772
773         hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
774         if (hr != ERROR_OK)
775                 goto exit;
776
777         hr = target_write_u32(target, wa->address, sromapi_req);
778         if (hr != ERROR_OK)
779                 goto exit_free_wa;
780
781         hr = target_write_u32(target,
782                         wa->address + 0x04,
783                         0x106);
784         if (hr != ERROR_OK)
785                 goto exit_free_wa;
786
787         hr = target_write_u32(target, wa->address + 0x08, addr);
788         if (hr != ERROR_OK)
789                 goto exit_free_wa;
790
791         hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
792         if (hr != ERROR_OK)
793                 goto exit_free_wa;
794
795         hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer);
796         if (hr != ERROR_OK)
797                 goto exit_free_wa;
798
799         hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
800
801 exit_free_wa:
802         target_free_working_area(target, wa);
803
804 exit:
805         return hr;
806 }
807
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)
820 {
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;
825
826         uint8_t page_buf[psoc6_info->row_sz];
827
828         hr = sromalgo_prepare(target);
829         if (hr != ERROR_OK)
830                 goto exit;
831
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);
836
837                 memset(page_buf, 0, sizeof(page_buf));
838                 memcpy(&page_buf[row_offset], buffer, row_bytes);
839
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;
844                 }
845
846                 buffer += row_bytes;
847                 offset += row_bytes;
848                 count -= row_bytes;
849         }
850
851 exit:
852         sromalgo_release(target);
853         return hr;
854 }
855
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)
861 {
862         if (CMD_ARGC != 1)
863                 return ERROR_COMMAND_SYNTAX_ERROR;
864
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;
869
870         hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
871
872         return hr;
873 }
874
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.
882  *
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)
887 {
888         int hr;
889         uint32_t reset_addr;
890         bool is_cm0 = (target->coreid == 0);
891
892         /* Halt target device */
893         if (target->state != TARGET_HALTED) {
894                 hr = target_halt(target);
895                 if (hr != ERROR_OK)
896                         return hr;
897
898                 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
899                 if (hr != ERROR_OK)
900                         return hr;
901         }
902
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;
909
910         /* Invalid value means flash is empty */
911         vt_base &= 0xFFFFFF00;
912         if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
913                 return ERROR_OK;
914
915         /* Read Reset Vector value*/
916         hr = target_read_u32(target, vt_base + 4, &reset_addr);
917         if (hr != ERROR_OK)
918                 return hr;
919
920         /* Invalid value means flash is empty */
921         if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
922                 return ERROR_OK;
923
924
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;
929
930         const struct armv7m_common *cm = target_to_armv7m(target);
931
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);
944         }
945
946         /* Wait 100ms for bootcode and reinitialize DAP */
947         usleep(100000);
948         dap_dp_init(cm->debug_ap->dap);
949
950         target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
951
952         /* Remove the break point */
953         breakpoint_remove(target, reset_addr);
954
955         return ERROR_OK;
956 }
957
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.
965  *
966  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
967  *************************************************************************************************/
968 COMMAND_HANDLER(psoc6_handle_reset_halt)
969 {
970         if (CMD_ARGC)
971                 return ERROR_COMMAND_SYNTAX_ERROR;
972
973         struct target *target = get_current_target(CMD_CTX);
974         return handle_reset_halt(target);
975 }
976
977 FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
978 {
979         struct psoc6_target_info *psoc6_info;
980         int hr = ERROR_OK;
981
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;
988         }
989         return hr;
990 }
991
992 static const struct command_registration psoc6_exec_command_handlers[] = {
993         {
994                 .name = "mass_erase",
995                 .handler = psoc6_handle_mass_erase_command,
996                 .mode = COMMAND_EXEC,
997                 .usage = "bank",
998                 .help = "Erases entire Main Flash",
999         },
1000         {
1001                 .name = "reset_halt",
1002                 .handler = psoc6_handle_reset_halt,
1003                 .mode = COMMAND_EXEC,
1004                 .usage = "",
1005                 .help = "Tries to simulate broken Vector Catch",
1006         },
1007         COMMAND_REGISTRATION_DONE
1008 };
1009
1010 static const struct command_registration psoc6_command_handlers[] = {
1011         {
1012                 .name = "psoc6",
1013                 .mode = COMMAND_ANY,
1014                 .help = "PSoC 6 flash command group",
1015                 .usage = "",
1016                 .chain = psoc6_exec_command_handlers,
1017         },
1018         COMMAND_REGISTRATION_DONE
1019 };
1020
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,
1035 };