flash/nor/psoc6: remove setting of xPSR.T bit from sromalgo_prepare()
[fw/openocd] / src / flash / nor / psoc6.c
1 /***************************************************************************
2  *                                                                         *
3  *   Copyright (C) 2018 by Bohdan Tymkiv                                   *
4  *   bohdan.tymkiv@cypress.com bohdan200@gmail.com                         *
5  *                                                                         *
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.                                   *
10  *                                                                         *
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.                          *
15  *                                                                         *
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  ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <time.h>
25
26 #include "imp.h"
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"
33
34 /**************************************************************************************************
35  * PSoC6 device definitions
36  *************************************************************************************************/
37 #define MFLASH_SECTOR_SIZE              (256u * 1024u)
38 #define WFLASH_SECTOR_SIZE              (32u * 1024u)
39
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
46
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
52
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)
60
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
67
68 #define IPC_ID                          2u
69 #define IPC_INTR_ID                     0u
70 #define IPC_TIMEOUT_MS                  1000
71
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
80
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
85
86 struct psoc6_target_info {
87         uint32_t silicon_id;
88         uint8_t protection;
89         uint32_t main_flash_sz;
90         uint32_t row_sz;
91         bool is_probed;
92 };
93
94 struct timeout {
95         int64_t start_time;
96         long timeout_ms;
97 };
98
99 struct row_region {
100         uint32_t addr;
101         size_t size;
102 };
103
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 */
109 };
110
111 #define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
112
113 static struct working_area *g_stack_area;
114 static struct armv7m_algorithm g_armv7m_info;
115
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)
122 {
123         to->start_time = timeval_ms();
124         to->timeout_ms = timeout_ms;
125 }
126
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)
133 {
134         return (timeval_ms() - to->start_time) > to->timeout_ms;
135 }
136
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.
141  *
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)
146 {
147         int hr;
148
149         /* Initialize Vector Table Offset register (in case FW modified it) */
150         hr = target_write_u32(target, 0xE000ED08, 0x00000000);
151         if (hr != ERROR_OK)
152                 return hr;
153
154         /* Allocate Working Area for Stack and Flash algorithm */
155         hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
156         if (hr != ERROR_OK)
157                 return hr;
158
159         g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
160         g_armv7m_info.core_mode = ARM_MODE_THREAD;
161
162         struct reg_param reg_params;
163         init_reg_param(&reg_params, "sp", 32, PARAM_OUT);
164         buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size);
165
166         /* Write basic infinite loop algorithm to target RAM */
167         hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7);
168         if (hr != ERROR_OK)
169                 goto destroy_rp_free_wa;
170
171         hr = target_start_algorithm(target, 0, NULL, 1, &reg_params, g_stack_area->address,
172                         0, &g_armv7m_info);
173         if (hr != ERROR_OK)
174                 goto destroy_rp_free_wa;
175
176         destroy_reg_param(&reg_params);
177
178         return hr;
179
180 destroy_rp_free_wa:
181         /* Something went wrong, do some cleanup */
182         destroy_reg_param(&reg_params);
183
184         if (g_stack_area) {
185                 target_free_working_area(target, g_stack_area);
186                 g_stack_area = NULL;
187         }
188
189         return hr;
190 }
191
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.
196  *
197  * @param target current target
198  *************************************************************************************************/
199 static void sromalgo_release(struct target *target)
200 {
201         int hr = ERROR_OK;
202
203         if (g_stack_area) {
204                 /* Stop flash algorithm if it is running */
205                 if (target->running_alg) {
206                         hr = target_halt(target);
207                         if (hr != ERROR_OK)
208                                 goto exit_free_wa;
209
210                         hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
211                                         IPC_TIMEOUT_MS, &g_armv7m_info);
212                         if (hr != ERROR_OK)
213                                 goto exit_free_wa;
214                 }
215
216 exit_free_wa:
217                 /* Free Stack/Flash algorithm working area */
218                 target_free_working_area(target, g_stack_area);
219                 g_stack_area = NULL;
220         }
221 }
222
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
228  * in expected state
229  *
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)
236 {
237         int hr;
238         uint32_t reg_val;
239
240         struct timeout to;
241         timeout_init(&to, IPC_TIMEOUT_MS);
242
243         while (!timeout_expired(&to)) {
244                 /* Process any server requests */
245                 keep_alive();
246
247                 /* Read IPC Lock status */
248                 hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), &reg_val);
249                 if (hr != ERROR_OK) {
250                         LOG_ERROR("Unable to read IPC Lock Status register");
251                         return hr;
252                 }
253
254                 bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
255
256                 if (lock_expected == is_locked)
257                         return ERROR_OK;
258         }
259
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.");
263         }
264
265         LOG_ERROR("Timeout polling IPC Lock Status");
266         return ERROR_TARGET_TIMEOUT;
267 }
268
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.
274  *
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)
280 {
281         int hr = ERROR_OK;
282         bool is_acquired = false;
283         uint32_t reg_val;
284
285         struct timeout to;
286         timeout_init(&to, IPC_TIMEOUT_MS);
287
288         while (!timeout_expired(&to)) {
289                 keep_alive();
290
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");
294                         return hr;
295                 }
296
297                 /* Check if data is written on first step */
298                 hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), &reg_val);
299                 if (hr != ERROR_OK) {
300                         LOG_ERROR("Unable to read IPC Acquire register");
301                         return hr;
302                 }
303
304                 is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
305                 if (is_acquired) {
306                         /* If IPC structure is acquired, the lock status should be set */
307                         hr = ipc_poll_lock_stat(target, ipc_id, true);
308                         break;
309                 }
310         }
311
312         if (!is_acquired)
313                 LOG_ERROR("Timeout acquiring IPC structure");
314
315         return hr;
316 }
317
318 /** ***********************************************************************************************
319  * @brief Invokes SROM API functions which are responsible for Flash operations
320  *
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,
330         uint32_t *data_out)
331 {
332         int hr;
333
334         bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
335
336         hr = ipc_acquire(target, IPC_ID);
337         if (hr != ERROR_OK)
338                 return hr;
339
340         if (is_data_in_ram)
341                 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area);
342         else
343                 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params);
344
345         if (hr != ERROR_OK)
346                 return hr;
347
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));
350         if (hr != ERROR_OK)
351                 return hr;
352
353         hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
354         if (hr != ERROR_OK)
355                 return hr;
356
357         /* Poll lock status */
358         hr = ipc_poll_lock_stat(target, IPC_ID, false);
359         if (hr != ERROR_OK)
360                 return hr;
361
362         /* Poll Data byte */
363         if (is_data_in_ram)
364                 hr = target_read_u32(target, working_area, data_out);
365         else
366                 hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out);
367
368         if (hr != ERROR_OK) {
369                 LOG_ERROR("Error reading SROM API Status location");
370                 return hr;
371         }
372
373         bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS;
374         if (!is_success) {
375                 LOG_ERROR("SROM API execution failed. Status: 0x%08" PRIX32, *data_out);
376                 return ERROR_TARGET_FAILURE;
377         }
378
379         return ERROR_OK;
380 }
381
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)
390 {
391         int hr;
392         uint32_t family_rev, siid_prot;
393
394         hr = sromalgo_prepare(target);
395         if (hr != ERROR_OK)
396                 goto exit;
397
398         /* Read FamilyID and Revision */
399         hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev);
400         if (hr != ERROR_OK)
401                 goto exit;
402
403         /* Read SiliconID and Protection */
404         hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
405         if (hr != ERROR_OK)
406                 goto exit;
407
408         *si_id  = (siid_prot & 0x0000FFFF) << 16;
409         *si_id |= (family_rev & 0x00FF0000) >> 8;
410         *si_id |= (family_rev & 0x000000FF) >> 0;
411
412         *protection = (siid_prot & 0x000F0000) >> 0x10;
413
414 exit:
415         sromalgo_release(target);
416         return ERROR_OK;
417 }
418
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)
425 {
426         int is_protected;
427
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);
430         if (hr != ERROR_OK)
431                 return hr;
432
433         switch (psoc6_info->protection) {
434                 case PROTECTION_VIRGIN:
435                 case PROTECTION_NORMAL:
436                         is_protected = 0;
437                         break;
438
439                 case PROTECTION_UNKNOWN:
440                 case PROTECTION_SECURE:
441                 case PROTECTION_DEAD:
442                 default:
443                         is_protected = 1;
444                         break;
445         }
446
447         for (unsigned int i = 0; i < bank->num_sectors; i++)
448                 bank->sectors[i].is_protected = is_protected;
449
450         return ERROR_OK;
451 }
452
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,
458                 unsigned int last)
459 {
460         (void)bank;
461         (void)set;
462         (void)first;
463         (void)last;
464
465         LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
466         return ERROR_OK;
467 }
468
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)
475 {
476         switch (protection) {
477                 case PROTECTION_VIRGIN:
478                         return "VIRGIN";
479                 case PROTECTION_NORMAL:
480                         return "NORMAL";
481                 case PROTECTION_SECURE:
482                         return "SECURE";
483                 case PROTECTION_DEAD:
484                         return "DEAD";
485                 case PROTECTION_UNKNOWN:
486                 default:
487                         return "UNKNOWN";
488         }
489 }
490
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)
499 {
500         struct psoc6_target_info *psoc6_info = bank->driver_priv;
501
502         if (psoc6_info->is_probed == false)
503                 return ERROR_FAIL;
504
505         int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
506         if (hr != ERROR_OK)
507                 return hr;
508
509         snprintf(buf, buf_size,
510                 "PSoC6 Silicon ID: 0x%08" PRIX32 "\n"
511                 "Protection: %s\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);
517
518         return ERROR_OK;
519 }
520
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)
527 {
528         for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
529                 if (bank->base == safe_sflash_regions[i].addr)
530                         return true;
531         }
532
533         return false;
534 }
535
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)
542 {
543         return (bank->base == MEM_BASE_WFLASH);
544 }
545
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)
552 {
553         return (bank->base == MEM_BASE_MFLASH);
554 }
555
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)
560  *
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)
565 {
566         struct target *target = bank->target;
567         struct psoc6_target_info *psoc6_info = bank->driver_priv;
568
569         int hr = ERROR_OK;
570
571         /* Retrieve data from SPCIF_GEOMETRY */
572         uint32_t geom;
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);
578
579         /* Calculate size of Main Flash*/
580         uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz;
581
582         free(bank->sectors);
583         bank->sectors = NULL;
584
585         size_t bank_size = 0;
586
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;
595                                 break;
596                         }
597                 }
598         }
599
600         if (bank_size == 0) {
601                 LOG_ERROR("Invalid Flash Bank base address in config file");
602                 return ERROR_FLASH_BANK_INVALID;
603         }
604
605         unsigned int num_sectors = bank_size / row_sz;
606         bank->size = bank_size;
607         bank->chip_width = 4;
608         bank->bus_width = 4;
609         bank->erased_value = 0;
610         bank->default_padded_value = 0;
611
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;
619         }
620
621         psoc6_info->is_probed = true;
622         psoc6_info->main_flash_sz = flash_sz_bytes;
623         psoc6_info->row_sz = row_sz;
624
625         return hr;
626 }
627
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)
634 {
635         struct psoc6_target_info *psoc6_info = bank->driver_priv;
636         int hr;
637
638         if (psoc6_info->is_probed)
639                 hr = ERROR_OK;
640         else
641                 hr = psoc6_probe(bank);
642
643         return hr;
644 }
645
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)
654 {
655         struct target *target = bank->target;
656
657         LOG_DEBUG("Erasing SECTOR @%08" PRIX32, addr);
658
659         int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ);
660         if (hr != ERROR_OK)
661                 return hr;
662
663         hr = target_write_u32(target, wa->address + 0x04, addr);
664         if (hr != ERROR_OK)
665                 return hr;
666
667         uint32_t data_out;
668         hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out);
669         if (hr != ERROR_OK)
670                 LOG_ERROR("SECTOR @%08" PRIX32 " not erased!", addr);
671
672         return hr;
673 }
674
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)
683 {
684         struct target *target = bank->target;
685
686         LOG_DEBUG("Erasing ROW @%08" PRIX32, addr);
687
688         int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ);
689         if (hr != ERROR_OK)
690                 return hr;
691
692         hr = target_write_u32(target, wa->address + 0x04, addr);
693         if (hr != ERROR_OK)
694                 return hr;
695
696         uint32_t data_out;
697         hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out);
698         if (hr != ERROR_OK)
699                 LOG_ERROR("ROW @%08" PRIX32 " not erased!", addr);
700
701         return hr;
702 }
703
704 /** ***********************************************************************************************
705  * @brief Performs Erase operation. Function will try to use biggest erase block possible to
706  * speedup the operation.
707  *
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,
714                 unsigned int last)
715 {
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;
719
720         int hr;
721         struct working_area *wa;
722
723         if (is_sflash_bank(bank)) {
724                 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
725                 return ERROR_OK;
726         }
727
728         hr = sromalgo_prepare(target);
729         if (hr != ERROR_OK)
730                 goto exit;
731
732         hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
733         if (hr != ERROR_OK)
734                 goto exit;
735
736         /* Number of rows in single sector */
737         const unsigned int rows_in_sector = sector_size / psoc6_info->row_sz;
738
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);
744                         if (hr != ERROR_OK)
745                                 goto exit_free_wa;
746
747                         for (unsigned int i = first; i < first + rows_in_sector; i++)
748                                 bank->sectors[i].is_erased = 1;
749
750                         first += rows_in_sector;
751                 } else {
752                         /* Perform Row Erase otherwise */
753                         hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz);
754                         if (hr != ERROR_OK)
755                                 goto exit_free_wa;
756
757                         bank->sectors[first].is_erased = 1;
758                         first += 1;
759                 }
760         }
761
762 exit_free_wa:
763         target_free_working_area(target, wa);
764 exit:
765         sromalgo_release(target);
766         return hr;
767 }
768
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,
778         uint32_t addr,
779         const uint8_t *buffer,
780         bool is_sflash)
781 {
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;
786         uint32_t data_out;
787         int hr = ERROR_OK;
788
789         LOG_DEBUG("Programming ROW @%08" PRIX32, addr);
790
791         hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
792         if (hr != ERROR_OK)
793                 goto exit;
794
795         hr = target_write_u32(target, wa->address, sromapi_req);
796         if (hr != ERROR_OK)
797                 goto exit_free_wa;
798
799         hr = target_write_u32(target,
800                         wa->address + 0x04,
801                         0x106);
802         if (hr != ERROR_OK)
803                 goto exit_free_wa;
804
805         hr = target_write_u32(target, wa->address + 0x08, addr);
806         if (hr != ERROR_OK)
807                 goto exit_free_wa;
808
809         hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
810         if (hr != ERROR_OK)
811                 goto exit_free_wa;
812
813         hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer);
814         if (hr != ERROR_OK)
815                 goto exit_free_wa;
816
817         hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
818
819 exit_free_wa:
820         target_free_working_area(target, wa);
821
822 exit:
823         return hr;
824 }
825
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,
836         uint32_t offset,
837         uint32_t count)
838 {
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);
842         int hr;
843
844         uint8_t page_buf[psoc6_info->row_sz];
845
846         hr = sromalgo_prepare(target);
847         if (hr != ERROR_OK)
848                 goto exit;
849
850         while (count) {
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);
854
855                 memset(page_buf, 0, sizeof(page_buf));
856                 memcpy(&page_buf[row_offset], buffer, row_bytes);
857
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);
861                         goto exit;
862                 }
863
864                 buffer += row_bytes;
865                 offset += row_bytes;
866                 count -= row_bytes;
867         }
868
869 exit:
870         sromalgo_release(target);
871         return hr;
872 }
873
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)
880 {
881         if (CMD_ARGC != 1)
882                 return ERROR_COMMAND_SYNTAX_ERROR;
883
884         struct flash_bank *bank;
885         int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
886         if (hr != ERROR_OK)
887                 return hr;
888
889         hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
890
891         return hr;
892 }
893
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.
901  *
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)
906 {
907         int hr;
908         uint32_t reset_addr;
909         bool is_cm0 = (target->coreid == 0);
910
911         /* Halt target device */
912         if (target->state != TARGET_HALTED) {
913                 hr = target_halt(target);
914                 if (hr != ERROR_OK)
915                         return hr;
916
917                 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
918                 if (hr != ERROR_OK)
919                         return hr;
920         }
921
922         /* Read Vector Offset register */
923         uint32_t vt_base;
924         const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
925         hr = target_read_u32(target, vt_offset_reg, &vt_base);
926         if (hr != ERROR_OK)
927                 return ERROR_OK;
928
929         /* Invalid value means flash is empty */
930         vt_base &= 0xFFFFFF00;
931         if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
932                 return ERROR_OK;
933
934         /* Read Reset Vector value*/
935         hr = target_read_u32(target, vt_base + 4, &reset_addr);
936         if (hr != ERROR_OK)
937                 return hr;
938
939         /* Invalid value means flash is empty */
940         if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
941                 return ERROR_OK;
942
943
944         /* Set breakpoint at User Application entry point */
945         hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD);
946         if (hr != ERROR_OK)
947                 return hr;
948
949         const struct armv7m_common *cm = target_to_armv7m(target);
950
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 */
954         if (is_cm0) {
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);
959         } else {
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);
963         }
964
965         /* Wait 100ms for bootcode and reinitialize DAP */
966         usleep(100000);
967         dap_dp_init(cm->debug_ap->dap);
968
969         target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
970
971         /* Remove the break point */
972         breakpoint_remove(target, reset_addr);
973
974         return ERROR_OK;
975 }
976
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.
984  *
985  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
986  *************************************************************************************************/
987 COMMAND_HANDLER(psoc6_handle_reset_halt)
988 {
989         if (CMD_ARGC)
990                 return ERROR_COMMAND_SYNTAX_ERROR;
991
992         struct target *target = get_current_target(CMD_CTX);
993         return handle_reset_halt(target);
994 }
995
996 FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
997 {
998         struct psoc6_target_info *psoc6_info;
999         int hr = ERROR_OK;
1000
1001         if (CMD_ARGC < 6)
1002                 hr = ERROR_COMMAND_SYNTAX_ERROR;
1003         else {
1004                 psoc6_info = calloc(1, sizeof(struct psoc6_target_info));
1005                 psoc6_info->is_probed = false;
1006                 bank->driver_priv = psoc6_info;
1007         }
1008         return hr;
1009 }
1010
1011 static const struct command_registration psoc6_exec_command_handlers[] = {
1012         {
1013                 .name = "mass_erase",
1014                 .handler = psoc6_handle_mass_erase_command,
1015                 .mode = COMMAND_EXEC,
1016                 .usage = "bank",
1017                 .help = "Erases entire Main Flash",
1018         },
1019         {
1020                 .name = "reset_halt",
1021                 .handler = psoc6_handle_reset_halt,
1022                 .mode = COMMAND_EXEC,
1023                 .usage = NULL,
1024                 .help = "Tries to simulate broken Vector Catch",
1025         },
1026         COMMAND_REGISTRATION_DONE
1027 };
1028
1029 static const struct command_registration psoc6_command_handlers[] = {
1030         {
1031                 .name = "psoc6",
1032                 .mode = COMMAND_ANY,
1033                 .help = "PSoC 6 flash command group",
1034                 .usage = "",
1035                 .chain = psoc6_exec_command_handlers,
1036         },
1037         COMMAND_REGISTRATION_DONE
1038 };
1039
1040 const struct flash_driver psoc6_flash = {
1041         .name = "psoc6",
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,
1054 };