flash: fix typos and duplicated words
[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         /* Restore THUMB bit in xPSR register */
155         const struct armv7m_common *cm = target_to_armv7m(target);
156         hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000);
157         if (hr != ERROR_OK)
158                 return hr;
159
160         /* Allocate Working Area for Stack and Flash algorithm */
161         hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
162         if (hr != ERROR_OK)
163                 return hr;
164
165         g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
166         g_armv7m_info.core_mode = ARM_MODE_THREAD;
167
168         struct reg_param reg_params;
169         init_reg_param(&reg_params, "sp", 32, PARAM_OUT);
170         buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size);
171
172         /* Write basic infinite loop algorithm to target RAM */
173         hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7);
174         if (hr != ERROR_OK)
175                 goto destroy_rp_free_wa;
176
177         hr = target_start_algorithm(target, 0, NULL, 1, &reg_params, g_stack_area->address,
178                         0, &g_armv7m_info);
179         if (hr != ERROR_OK)
180                 goto destroy_rp_free_wa;
181
182         destroy_reg_param(&reg_params);
183
184         return hr;
185
186 destroy_rp_free_wa:
187         /* Something went wrong, do some cleanup */
188         destroy_reg_param(&reg_params);
189
190         if (g_stack_area) {
191                 target_free_working_area(target, g_stack_area);
192                 g_stack_area = NULL;
193         }
194
195         return hr;
196 }
197
198 /** ***********************************************************************************************
199  * @brief Stops running flash algorithm and releases associated resources.
200  * This function is also used for cleanup in case of errors so g_stack_area may be NULL.
201  * These cases have to be handled gracefully.
202  *
203  * @param target current target
204  *************************************************************************************************/
205 static void sromalgo_release(struct target *target)
206 {
207         int hr = ERROR_OK;
208
209         if (g_stack_area) {
210                 /* Stop flash algorithm if it is running */
211                 if (target->running_alg) {
212                         hr = target_halt(target);
213                         if (hr != ERROR_OK)
214                                 goto exit_free_wa;
215
216                         hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
217                                         IPC_TIMEOUT_MS, &g_armv7m_info);
218                         if (hr != ERROR_OK)
219                                 goto exit_free_wa;
220                 }
221
222 exit_free_wa:
223                 /* Free Stack/Flash algorithm working area */
224                 target_free_working_area(target, g_stack_area);
225                 g_stack_area = NULL;
226         }
227 }
228
229 /** ***********************************************************************************************
230  * @brief Waits for expected IPC lock status. PSoC6 uses IPC structures for inter-core
231  * communication. Same IPCs are used to invoke SROM API. IPC structure must be locked prior to
232  * invoking any SROM API. This ensures nothing else in the system will use same IPC thus corrupting
233  * our data. Locking is performed by ipc_acquire(), this function ensures that IPC is actually
234  * in expected state
235  *
236  * @param target current target
237  * @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access
238  * @param lock_expected expected lock status
239  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
240  *************************************************************************************************/
241 static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected)
242 {
243         int hr;
244         uint32_t reg_val;
245
246         struct timeout to;
247         timeout_init(&to, IPC_TIMEOUT_MS);
248
249         while (!timeout_expired(&to)) {
250                 /* Process any server requests */
251                 keep_alive();
252
253                 /* Read IPC Lock status */
254                 hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), &reg_val);
255                 if (hr != ERROR_OK) {
256                         LOG_ERROR("Unable to read IPC Lock Status register");
257                         return hr;
258                 }
259
260                 bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
261
262                 if (lock_expected == is_locked)
263                         return ERROR_OK;
264         }
265
266         if (target->coreid) {
267                 LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. "
268                         "Please perform all Flash-related operations via CM0+ target on dual-core devices.");
269         }
270
271         LOG_ERROR("Timeout polling IPC Lock Status");
272         return ERROR_TARGET_TIMEOUT;
273 }
274
275 /** ***********************************************************************************************
276  * @brief Acquires IPC structure. PSoC6 uses IPC structures for inter-core communication.
277  * Same IPCs are used to invoke SROM API. IPC structure must be locked prior to invoking any SROM API.
278  * This ensures nothing else in the system will use same IPC thus corrupting our data.
279  * This function locks the IPC.
280  *
281  * @param target current target
282  * @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP access
283  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
284  *************************************************************************************************/
285 static int ipc_acquire(struct target *target, char ipc_id)
286 {
287         int hr = ERROR_OK;
288         bool is_acquired = false;
289         uint32_t reg_val;
290
291         struct timeout to;
292         timeout_init(&to, IPC_TIMEOUT_MS);
293
294         while (!timeout_expired(&to)) {
295                 keep_alive();
296
297                 hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), IPC_ACQUIRE_SUCCESS_MSK);
298                 if (hr != ERROR_OK) {
299                         LOG_ERROR("Unable to write to IPC Acquire register");
300                         return hr;
301                 }
302
303                 /* Check if data is written on first step */
304                 hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), &reg_val);
305                 if (hr != ERROR_OK) {
306                         LOG_ERROR("Unable to read IPC Acquire register");
307                         return hr;
308                 }
309
310                 is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
311                 if (is_acquired) {
312                         /* If IPC structure is acquired, the lock status should be set */
313                         hr = ipc_poll_lock_stat(target, ipc_id, true);
314                         break;
315                 }
316         }
317
318         if (!is_acquired)
319                 LOG_ERROR("Timeout acquiring IPC structure");
320
321         return hr;
322 }
323
324 /** ***********************************************************************************************
325  * @brief Invokes SROM API functions which are responsible for Flash operations
326  *
327  * @param target current target
328  * @param req_and_params request id of the function to invoke
329  * @param working_area address of memory buffer in target's memory space for SROM API parameters
330  * @param data_out pointer to variable which will be populated with execution status
331  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
332  *************************************************************************************************/
333 static int call_sromapi(struct target *target,
334         uint32_t req_and_params,
335         uint32_t working_area,
336         uint32_t *data_out)
337 {
338         int hr;
339
340         bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
341
342         hr = ipc_acquire(target, IPC_ID);
343         if (hr != ERROR_OK)
344                 return hr;
345
346         if (is_data_in_ram)
347                 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area);
348         else
349                 hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params);
350
351         if (hr != ERROR_OK)
352                 return hr;
353
354         /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */
355         hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + IPC_ID));
356         if (hr != ERROR_OK)
357                 return hr;
358
359         hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
360         if (hr != ERROR_OK)
361                 return hr;
362
363         /* Poll lock status */
364         hr = ipc_poll_lock_stat(target, IPC_ID, false);
365         if (hr != ERROR_OK)
366                 return hr;
367
368         /* Poll Data byte */
369         if (is_data_in_ram)
370                 hr = target_read_u32(target, working_area, data_out);
371         else
372                 hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out);
373
374         if (hr != ERROR_OK) {
375                 LOG_ERROR("Error reading SROM API Status location");
376                 return hr;
377         }
378
379         bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS;
380         if (!is_success) {
381                 LOG_ERROR("SROM API execution failed. Status: 0x%08X", (uint32_t)*data_out);
382                 return ERROR_TARGET_FAILURE;
383         }
384
385         return ERROR_OK;
386 }
387
388 /** ***********************************************************************************************
389  * @brief Retrieves SiliconID and Protection status of the target device
390  * @param target current target
391  * @param si_id pointer to variable, will be populated with SiliconID
392  * @param protection pointer to variable, will be populated with protection status
393  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
394  *************************************************************************************************/
395 static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection)
396 {
397         int hr;
398         uint32_t family_rev, siid_prot;
399
400         hr = sromalgo_prepare(target);
401         if (hr != ERROR_OK)
402                 goto exit;
403
404         /* Read FamilyID and Revision */
405         hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev);
406         if (hr != ERROR_OK)
407                 goto exit;
408
409         /* Read SiliconID and Protection */
410         hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
411         if (hr != ERROR_OK)
412                 goto exit;
413
414         *si_id  = (siid_prot & 0x0000FFFF) << 16;
415         *si_id |= (family_rev & 0x00FF0000) >> 8;
416         *si_id |= (family_rev & 0x000000FF) >> 0;
417
418         *protection = (siid_prot & 0x000F0000) >> 0x10;
419
420 exit:
421         sromalgo_release(target);
422         return ERROR_OK;
423 }
424
425 /** ***********************************************************************************************
426  * @brief Translates Protection status to openocd-friendly boolean value
427  * @param bank current flash bank
428  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
429  *************************************************************************************************/
430 static int psoc6_protect_check(struct flash_bank *bank)
431 {
432         int is_protected;
433
434         struct psoc6_target_info *psoc6_info = bank->driver_priv;
435         int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
436         if (hr != ERROR_OK)
437                 return hr;
438
439         switch (psoc6_info->protection) {
440                 case PROTECTION_VIRGIN:
441                 case PROTECTION_NORMAL:
442                         is_protected = 0;
443                         break;
444
445                 case PROTECTION_UNKNOWN:
446                 case PROTECTION_SECURE:
447                 case PROTECTION_DEAD:
448                 default:
449                         is_protected = 1;
450                         break;
451         }
452
453         for (unsigned int i = 0; i < bank->num_sectors; i++)
454                 bank->sectors[i].is_protected = is_protected;
455
456         return ERROR_OK;
457 }
458
459 /** ***********************************************************************************************
460  * @brief Dummy function, Life Cycle transition is not currently supported
461  * @return ERROR_OK always
462  *************************************************************************************************/
463 static int psoc6_protect(struct flash_bank *bank, int set, unsigned int first,
464                 unsigned int last)
465 {
466         (void)bank;
467         (void)set;
468         (void)first;
469         (void)last;
470
471         LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
472         return ERROR_OK;
473 }
474
475 /** ***********************************************************************************************
476  * @brief Translates Protection status to string
477  * @param protection protection value
478  * @return pointer to const string describing protection status
479  *************************************************************************************************/
480 static const char *protection_to_str(uint8_t protection)
481 {
482         switch (protection) {
483                 case PROTECTION_VIRGIN:
484                         return "VIRGIN";
485                 case PROTECTION_NORMAL:
486                         return "NORMAL";
487                 case PROTECTION_SECURE:
488                         return "SECURE";
489                 case PROTECTION_DEAD:
490                         return "DEAD";
491                 case PROTECTION_UNKNOWN:
492                 default:
493                         return "UNKNOWN";
494         }
495 }
496
497 /** ***********************************************************************************************
498  * @brief psoc6_get_info Displays human-readable information about acquired device
499  * @param bank current flash bank
500  * @param buf pointer to buffer for human-readable text
501  * @param buf_size size of the buffer
502  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
503  *************************************************************************************************/
504 static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size)
505 {
506         struct psoc6_target_info *psoc6_info = bank->driver_priv;
507
508         if (psoc6_info->is_probed == false)
509                 return ERROR_FAIL;
510
511         int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
512         if (hr != ERROR_OK)
513                 return hr;
514
515         snprintf(buf, buf_size,
516                 "PSoC6 Silicon ID: 0x%08X\n"
517                 "Protection: %s\n"
518                 "Main Flash size: %d kB\n"
519                 "Work Flash size: 32 kB\n",
520                 psoc6_info->silicon_id,
521                 protection_to_str(psoc6_info->protection),
522                 psoc6_info->main_flash_sz / 1024);
523
524         return ERROR_OK;
525 }
526
527 /** ***********************************************************************************************
528  * @brief Checks if given flash bank belongs to Supervisory Flash
529  * @param bank current flash bank
530  * @return true if flash bank belongs to Supervisory Flash
531  *************************************************************************************************/
532 static bool is_sflash_bank(struct flash_bank *bank)
533 {
534         for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
535                 if (bank->base == safe_sflash_regions[i].addr)
536                         return true;
537         }
538
539         return false;
540 }
541
542 /** ***********************************************************************************************
543  * @brief Checks if given flash bank belongs to Work Flash
544  * @param bank current flash bank
545  * @return true if flash bank belongs to Work Flash
546  *************************************************************************************************/
547 static inline bool is_wflash_bank(struct flash_bank *bank)
548 {
549         return (bank->base == MEM_BASE_WFLASH);
550 }
551
552 /** ***********************************************************************************************
553  * @brief Checks if given flash bank belongs to Main Flash
554  * @param bank current flash bank
555  * @return true if flash bank belongs to Main Flash
556  *************************************************************************************************/
557 static inline bool is_mflash_bank(struct flash_bank *bank)
558 {
559         return (bank->base == MEM_BASE_MFLASH);
560 }
561
562 /** ***********************************************************************************************
563  * @brief Probes the device and populates related data structures with target flash geometry data.
564  * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a
565  * running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers)
566  *
567  * @param bank current flash bank
568  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
569  *************************************************************************************************/
570 static int psoc6_probe(struct flash_bank *bank)
571 {
572         struct target *target = bank->target;
573         struct psoc6_target_info *psoc6_info = bank->driver_priv;
574
575         int hr = ERROR_OK;
576
577         /* Retrieve data from SPCIF_GEOMETRY */
578         uint32_t geom;
579         target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom);
580         uint32_t row_sz_lg2 = (geom & 0xF0) >> 4;
581         uint32_t row_sz = (0x01 << row_sz_lg2);
582         uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8);
583         uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24);
584
585         /* Calculate size of Main Flash*/
586         uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz;
587
588         if (bank->sectors) {
589                 free(bank->sectors);
590                 bank->sectors = NULL;
591         }
592
593         size_t bank_size = 0;
594
595         if (is_mflash_bank(bank))
596                 bank_size = flash_sz_bytes;
597         else if (is_wflash_bank(bank))
598                 bank_size = MEM_WFLASH_SIZE;
599         else if (is_sflash_bank(bank)) {
600                 for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
601                         if (safe_sflash_regions[i].addr == bank->base) {
602                                 bank_size = safe_sflash_regions[i].size;
603                                 break;
604                         }
605                 }
606         }
607
608         if (bank_size == 0) {
609                 LOG_ERROR("Invalid Flash Bank base address in config file");
610                 return ERROR_FLASH_BANK_INVALID;
611         }
612
613         unsigned int num_sectors = bank_size / row_sz;
614         bank->size = bank_size;
615         bank->chip_width = 4;
616         bank->bus_width = 4;
617         bank->erased_value = 0;
618         bank->default_padded_value = 0;
619
620         bank->num_sectors = num_sectors;
621         bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
622         for (unsigned int i = 0; i < num_sectors; i++) {
623                 bank->sectors[i].size = row_sz;
624                 bank->sectors[i].offset = i * row_sz;
625                 bank->sectors[i].is_erased = -1;
626                 bank->sectors[i].is_protected = -1;
627         }
628
629         psoc6_info->is_probed = true;
630         psoc6_info->main_flash_sz = flash_sz_bytes;
631         psoc6_info->row_sz = row_sz;
632
633         return hr;
634 }
635
636 /** ***********************************************************************************************
637  * @brief Probes target device only if it hasn't been probed yet
638  * @param bank current flash bank
639  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
640  *************************************************************************************************/
641 static int psoc6_auto_probe(struct flash_bank *bank)
642 {
643         struct psoc6_target_info *psoc6_info = bank->driver_priv;
644         int hr;
645
646         if (psoc6_info->is_probed)
647                 hr = ERROR_OK;
648         else
649                 hr = psoc6_probe(bank);
650
651         return hr;
652 }
653
654 /** ***********************************************************************************************
655  * @brief Erases single sector (256k) on target device
656  * @param bank current flash bank
657  * @param wa working area for SROM API parameters
658  * @param addr starting address of the sector
659  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
660  *************************************************************************************************/
661 static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
662 {
663         struct target *target = bank->target;
664
665         LOG_DEBUG("Erasing SECTOR @%08X", addr);
666
667         int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ);
668         if (hr != ERROR_OK)
669                 return hr;
670
671         hr = target_write_u32(target, wa->address + 0x04, addr);
672         if (hr != ERROR_OK)
673                 return hr;
674
675         uint32_t data_out;
676         hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out);
677         if (hr != ERROR_OK)
678                 LOG_ERROR("SECTOR @%08X not erased!", addr);
679
680         return hr;
681 }
682
683 /** ***********************************************************************************************
684  * @brief Erases single row (512b) on target device
685  * @param bank current flash bank
686  * @param wa working area for SROM API parameters
687  * @param addr starting address of the flash row
688  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
689  *************************************************************************************************/
690 static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
691 {
692         struct target *target = bank->target;
693
694         LOG_DEBUG("Erasing ROW @%08X", addr);
695
696         int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ);
697         if (hr != ERROR_OK)
698                 return hr;
699
700         hr = target_write_u32(target, wa->address + 0x04, addr);
701         if (hr != ERROR_OK)
702                 return hr;
703
704         uint32_t data_out;
705         hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out);
706         if (hr != ERROR_OK)
707                 LOG_ERROR("ROW @%08X not erased!", addr);
708
709         return hr;
710 }
711
712 /** ***********************************************************************************************
713  * @brief Performs Erase operation. Function will try to use biggest erase block possible to
714  * speedup the operation.
715  *
716  * @param bank current flash bank
717  * @param first first sector to erase
718  * @param last last sector to erase
719  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
720  *************************************************************************************************/
721 static int psoc6_erase(struct flash_bank *bank, unsigned int first,
722                 unsigned int last)
723 {
724         struct target *target = bank->target;
725         struct psoc6_target_info *psoc6_info = bank->driver_priv;
726         const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE : MFLASH_SECTOR_SIZE;
727
728         int hr;
729         struct working_area *wa;
730
731         if (is_sflash_bank(bank)) {
732                 LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
733                 return ERROR_OK;
734         }
735
736         hr = sromalgo_prepare(target);
737         if (hr != ERROR_OK)
738                 goto exit;
739
740         hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
741         if (hr != ERROR_OK)
742                 goto exit;
743
744         /* Number of rows in single sector */
745         const unsigned int rows_in_sector = sector_size / psoc6_info->row_sz;
746
747         while (last >= first) {
748                 /* Erase Sector if we are on sector boundary and erase size covers whole sector */
749                 if ((first % rows_in_sector) == 0 &&
750                         (last - first + 1) >= rows_in_sector) {
751                         hr = psoc6_erase_sector(bank, wa, bank->base + first * psoc6_info->row_sz);
752                         if (hr != ERROR_OK)
753                                 goto exit_free_wa;
754
755                         for (unsigned int i = first; i < first + rows_in_sector; i++)
756                                 bank->sectors[i].is_erased = 1;
757
758                         first += rows_in_sector;
759                 } else {
760                         /* Perform Row Erase otherwise */
761                         hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz);
762                         if (hr != ERROR_OK)
763                                 goto exit_free_wa;
764
765                         bank->sectors[first].is_erased = 1;
766                         first += 1;
767                 }
768         }
769
770 exit_free_wa:
771         target_free_working_area(target, wa);
772 exit:
773         sromalgo_release(target);
774         return hr;
775 }
776
777 /** ***********************************************************************************************
778  * @brief Programs single Flash Row
779  * @param bank current flash bank
780  * @param addr address of the flash row
781  * @param buffer pointer to the buffer with data
782  * @param is_sflash true if current flash bank belongs to Supervisory Flash
783  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
784  *************************************************************************************************/
785 static int psoc6_program_row(struct flash_bank *bank,
786         uint32_t addr,
787         const uint8_t *buffer,
788         bool is_sflash)
789 {
790         struct target *target = bank->target;
791         struct psoc6_target_info *psoc6_info = bank->driver_priv;
792         struct working_area *wa;
793         const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : SROMAPI_PROGRAMROW_REQ;
794         uint32_t data_out;
795         int hr = ERROR_OK;
796
797         LOG_DEBUG("Programming ROW @%08X", addr);
798
799         hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
800         if (hr != ERROR_OK)
801                 goto exit;
802
803         hr = target_write_u32(target, wa->address, sromapi_req);
804         if (hr != ERROR_OK)
805                 goto exit_free_wa;
806
807         hr = target_write_u32(target,
808                         wa->address + 0x04,
809                         0x106);
810         if (hr != ERROR_OK)
811                 goto exit_free_wa;
812
813         hr = target_write_u32(target, wa->address + 0x08, addr);
814         if (hr != ERROR_OK)
815                 goto exit_free_wa;
816
817         hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
818         if (hr != ERROR_OK)
819                 goto exit_free_wa;
820
821         hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer);
822         if (hr != ERROR_OK)
823                 goto exit_free_wa;
824
825         hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
826
827 exit_free_wa:
828         target_free_working_area(target, wa);
829
830 exit:
831         return hr;
832 }
833
834 /** ***********************************************************************************************
835  * @brief Performs Program operation
836  * @param bank current flash bank
837  * @param buffer pointer to the buffer with data
838  * @param offset starting offset in flash bank
839  * @param count number of bytes in buffer
840  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
841  *************************************************************************************************/
842 static int psoc6_program(struct flash_bank *bank,
843         const uint8_t *buffer,
844         uint32_t offset,
845         uint32_t count)
846 {
847         struct target *target = bank->target;
848         struct psoc6_target_info *psoc6_info = bank->driver_priv;
849         const bool is_sflash = is_sflash_bank(bank);
850         int hr;
851
852         uint8_t page_buf[psoc6_info->row_sz];
853
854         hr = sromalgo_prepare(target);
855         if (hr != ERROR_OK)
856                 goto exit;
857
858         while (count) {
859                 uint32_t row_offset = offset % psoc6_info->row_sz;
860                 uint32_t aligned_addr = bank->base + offset - row_offset;
861                 uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, count);
862
863                 memset(page_buf, 0, sizeof(page_buf));
864                 memcpy(&page_buf[row_offset], buffer, row_bytes);
865
866                 hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash);
867                 if (hr != ERROR_OK) {
868                         LOG_ERROR("Failed to program Flash at address 0x%08X", aligned_addr);
869                         goto exit;
870                 }
871
872                 buffer += row_bytes;
873                 offset += row_bytes;
874                 count -= row_bytes;
875         }
876
877 exit:
878         sromalgo_release(target);
879         return hr;
880 }
881
882 /** ***********************************************************************************************
883  * @brief Performs Mass Erase operation
884  * @param bank flash bank index to erase
885  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
886  *************************************************************************************************/
887 COMMAND_HANDLER(psoc6_handle_mass_erase_command)
888 {
889         if (CMD_ARGC != 1)
890                 return ERROR_COMMAND_SYNTAX_ERROR;
891
892         struct flash_bank *bank;
893         int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
894         if (hr != ERROR_OK)
895                 return hr;
896
897         hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
898
899         return hr;
900 }
901
902 /** ***********************************************************************************************
903  * @brief Simulates broken Vector Catch
904  * Function will try to determine entry point of user application. If it succeeds it will set HW
905  * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
906  * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
907  * reset CM4 anyway, so using SYSRESETREQ is safe here.
908  * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
909  *
910  * @param target current target
911  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
912  *************************************************************************************************/
913 int handle_reset_halt(struct target *target)
914 {
915         int hr;
916         uint32_t reset_addr;
917         bool is_cm0 = (target->coreid == 0);
918
919         /* Halt target device */
920         if (target->state != TARGET_HALTED) {
921                 hr = target_halt(target);
922                 if (hr != ERROR_OK)
923                         return hr;
924
925                 target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
926                 if (hr != ERROR_OK)
927                         return hr;
928         }
929
930         /* Read Vector Offset register */
931         uint32_t vt_base;
932         const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
933         hr = target_read_u32(target, vt_offset_reg, &vt_base);
934         if (hr != ERROR_OK)
935                 return ERROR_OK;
936
937         /* Invalid value means flash is empty */
938         vt_base &= 0xFFFFFF00;
939         if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
940                 return ERROR_OK;
941
942         /* Read Reset Vector value*/
943         hr = target_read_u32(target, vt_base + 4, &reset_addr);
944         if (hr != ERROR_OK)
945                 return hr;
946
947         /* Invalid value means flash is empty */
948         if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
949                 return ERROR_OK;
950
951
952         /* Set breakpoint at User Application entry point */
953         hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD);
954         if (hr != ERROR_OK)
955                 return hr;
956
957         const struct armv7m_common *cm = target_to_armv7m(target);
958
959         /* PSoC6 reboots immediately after issuing SYSRESETREQ / VECTRESET
960          * this disables SWD/JTAG pins momentarily and may break communication
961          * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */
962         if (is_cm0) {
963                 /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
964                 LOG_INFO("psoc6.cm0: bkpt @0x%08X, issuing SYSRESETREQ", reset_addr);
965                 mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
966                         AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
967         } else {
968                 LOG_INFO("psoc6.cm4: bkpt @0x%08X, issuing VECTRESET", reset_addr);
969                 mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
970                         AIRCR_VECTKEY | AIRCR_VECTRESET);
971         }
972
973         /* Wait 100ms for bootcode and reinitialize DAP */
974         usleep(100000);
975         dap_dp_init(cm->debug_ap->dap);
976
977         target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
978
979         /* Remove the break point */
980         breakpoint_remove(target, reset_addr);
981
982         return ERROR_OK;
983 }
984
985 /** ***********************************************************************************************
986  * @brief Simulates broken Vector Catch
987  * Function will try to determine entry point of user application. If it succeeds it will set HW
988  * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
989  * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
990  * reset CM4 anyway, so using SYSRESETREQ is safe here.
991  * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
992  *
993  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
994  *************************************************************************************************/
995 COMMAND_HANDLER(psoc6_handle_reset_halt)
996 {
997         if (CMD_ARGC)
998                 return ERROR_COMMAND_SYNTAX_ERROR;
999
1000         struct target *target = get_current_target(CMD_CTX);
1001         return handle_reset_halt(target);
1002 }
1003
1004 FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
1005 {
1006         struct psoc6_target_info *psoc6_info;
1007         int hr = ERROR_OK;
1008
1009         if (CMD_ARGC < 6)
1010                 hr = ERROR_COMMAND_SYNTAX_ERROR;
1011         else {
1012                 psoc6_info = calloc(1, sizeof(struct psoc6_target_info));
1013                 psoc6_info->is_probed = false;
1014                 bank->driver_priv = psoc6_info;
1015         }
1016         return hr;
1017 }
1018
1019 static const struct command_registration psoc6_exec_command_handlers[] = {
1020         {
1021                 .name = "mass_erase",
1022                 .handler = psoc6_handle_mass_erase_command,
1023                 .mode = COMMAND_EXEC,
1024                 .usage = "bank",
1025                 .help = "Erases entire Main Flash",
1026         },
1027         {
1028                 .name = "reset_halt",
1029                 .handler = psoc6_handle_reset_halt,
1030                 .mode = COMMAND_EXEC,
1031                 .usage = NULL,
1032                 .help = "Tries to simulate broken Vector Catch",
1033         },
1034         COMMAND_REGISTRATION_DONE
1035 };
1036
1037 static const struct command_registration psoc6_command_handlers[] = {
1038         {
1039                 .name = "psoc6",
1040                 .mode = COMMAND_ANY,
1041                 .help = "PSoC 6 flash command group",
1042                 .usage = "",
1043                 .chain = psoc6_exec_command_handlers,
1044         },
1045         COMMAND_REGISTRATION_DONE
1046 };
1047
1048 const struct flash_driver psoc6_flash = {
1049         .name = "psoc6",
1050         .commands = psoc6_command_handlers,
1051         .flash_bank_command = psoc6_flash_bank_command,
1052         .erase = psoc6_erase,
1053         .protect = psoc6_protect,
1054         .write = psoc6_program,
1055         .read = default_flash_read,
1056         .probe = psoc6_probe,
1057         .auto_probe = psoc6_auto_probe,
1058         .erase_check = default_flash_blank_check,
1059         .protect_check = psoc6_protect_check,
1060         .info = psoc6_get_info,
1061         .free_driver_priv = default_flash_free_driver_priv,
1062 };