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