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