This is an automated email from Gerrit.

Bohdan Tymkiv ([email protected]) just uploaded a new patch set to Gerrit, which 
you can find at http://openocd.zylin.com/4233

-- gerrit

commit b735bcf82c0582d8ab128e53c7ca2d2df6104e60
Author: Bohdan Tymkiv <[email protected]>
Date:   Mon Sep 25 14:25:22 2017 +0300

    Add support for Cypress PSoC6 family of devices
    
    * Tested on CY8CKIT-001 kit with PSoC6 daughter board.
    * Tested with several J-Link adapters (Ultra+, Basic)
    
    Change-Id: I0a818c231e5f0b270c7774037b38d23221d59417
    Signed-off-by: Bohdan Tymkiv <[email protected]>

diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 5a992fe..e11c347 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -41,6 +41,7 @@ NOR_DRIVERS = \
        %D%/ocl.c \
        %D%/pic32mx.c \
        %D%/psoc4.c \
+       %D%/psoc6.c \
        %D%/sim3x.c \
        %D%/spi.c \
        %D%/stmsmi.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 4ad1d92..b7c72d4 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -67,6 +67,7 @@ extern struct flash_driver tms470_flash;
 extern struct flash_driver virtual_flash;
 extern struct flash_driver xmc1xxx_flash;
 extern struct flash_driver xmc4xxx_flash;
+extern struct flash_driver psoc6_flash;
 
 /**
  * The list of built-in flash drivers.
@@ -120,6 +121,7 @@ static struct flash_driver *flash_drivers[] = {
        &virtual_flash,
        &xmc1xxx_flash,
        &xmc4xxx_flash,
+       &psoc6_flash,
        NULL,
 };
 
diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c
new file mode 100644
index 0000000..bcba9bc
--- /dev/null
+++ b/src/flash/nor/psoc6.c
@@ -0,0 +1,989 @@
+/***************************************************************************
+ *                                                                         *
+ *   Copyright (C) 2017 by Bohdan Tymkiv                                   *
+ *   [email protected] [email protected]                         *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <time.h>
+
+#include "imp.h"
+#include "target/cortex_m.h"
+#include "target/breakpoints.h"
+#include "target/target_type.h"
+
+/**************************************************************************************************
+ * PSoC6 device definitions
+ 
*************************************************************************************************/
+#define FLASH_ROW_SIZE                  512u
+#define FLASH_SECTOR_SIZE               (256u*1024u)
+#define FLASH_NUM_ROWS_IN_SECTOR        (FLASH_SECTOR_SIZE / FLASH_ROW_SIZE)
+#define MEM_BASE_MFLASH                 0x10000000u
+#define MEM_BASE_WFLASH                 0x14000000u
+#define MEM_BASE_SFLASH                 0x16000000u
+#define RAM_LOOP_WA_SIZE                2048u
+
+#define SFLASH_USER_INDEX               0
+#define SFLASH_NAR_INDEX                1
+#define SFLASH_KEY_INDEX                2
+#define SFLASH_TOC2_INDEX               3
+
+#define PROTECTION_UNKNOWN              0x00u
+#define PROTECTION_VIRGIN               0x01u
+#define PROTECTION_NORMAL               0x02u
+#define PROTECTION_SECURE               0x03u
+#define PROTECTION_DEAD                 0x04u
+
+#define MEM_BASE_IPC                    0x40230000u
+#define IPC_STRUCT_SIZE                 0x20u
+#define MEM_IPC(n)                      (MEM_BASE_IPC + (n) * IPC_STRUCT_SIZE)
+#define MEM_IPC_ACQUIRE(n)              (MEM_IPC(n) + 0x00u)
+#define MEM_IPC_NOTIFY(n)               (MEM_IPC(n) + 0x08u)
+#define MEM_IPC_DATA(n)                 (MEM_IPC(n) + 0x0Cu)
+#define MEM_IPC_LOCK_STATUS(n)          (MEM_IPC(n) + 0x10u)
+
+#define MEM_BASE_IPC_INTR               0x40231000u
+#define IPC_INTR_STRUCT_SIZE            0x20u
+#define MEM_IPC_INTR(n)                 (MEM_BASE_IPC_INTR + (n) * 
IPC_INTR_STRUCT_SIZE)
+#define MEM_IPC_INTR_MASK(n)            (MEM_IPC_INTR(n) + 0x08u)
+#define IPC_ACQUIRE_SUCCESS_MSK         0x80000000u
+#define IPC_LOCK_ACQUIRED_MSK           0x80000000u
+
+#define IPC_ID                          2u
+#define IPC_INTR_ID                     0u
+#define IPC_TIMEOUT_MS                  1000
+
+#define SROMAPI_SIID_REQ                    0x00000001u
+#define SROMAPI_SIID_REQ_FAMILY_REVISION    (SROMAPI_SIID_REQ | 0x000u)
+#define SROMAPI_SIID_REQ_SIID_PROTECTION    (SROMAPI_SIID_REQ | 0x100u)
+#define SROMAPI_WRITEROW_REQ                0x05000100u
+#define SROMAPI_PROGRAMROW_REQ              0x06000100u
+#define SROMAPI_ERASESECTOR_REQ             0x14000100u
+#define SROMAPI_ERASEALL_REQ                0x0A000100u
+#define SROMAPI_ERASEROW_REQ                0x1C000100u
+
+#define SROMAPI_STATUS_MSK                  0xF0000000u
+#define SROMAPI_STAT_SUCCESS                0xA0000000u
+#define SROMAPI_DATA_LOCATION_MSK           0x00000001u
+
+struct mxs40_chip_info_s {
+       uint32_t silicon_id;
+       const char *mpn_str;
+       uint32_t mainfl_kb;
+       uint32_t workfl_kb;
+};
+
+struct row_region_s {
+       uint32_t addr;
+       size_t size;
+};
+
+struct psoc6_target_info_s {
+       struct mxs40_chip_info_s *info;
+       uint32_t silicon_id;
+       uint32_t protection;
+       int is_probed;
+};
+
+struct timeout_s {
+       struct timespec start_time;
+       long timeout_ms;
+};
+
+/* Target memory layout */
+static struct mxs40_chip_info_s psoc6_devices[] = {
+       { 0xE2102100, "CY8C6036BZI-F04",   .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2112100, "CY8C6016BZI-F04",   .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2122100, "CY8C6116BZI-F54",   .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2132100, "CY8C6136BZI-F14",   .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2142100, "CY8C6136BZI-F34",   .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2152100, "CY8C6137BZI-F14",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2162100, "CY8C6137BZI-F34",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2172100, "CY8C6137BZI-F54",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2182100, "CY8C6117BZI-F34",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2192100, "CY8C6246BZI-D04",   .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE21A2100, "CY8C6247BZI-D44",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE21B2100, "CY8C6247BZI-D34",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2062100, "CY8C6247BZI-D54",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2001100, "CY8C637BZI-MD76",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2202100, "CY8C6336BZI-BLF03", .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2212100, "CY8C6316BZI-BLF03", .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2222100, "CY8C6316BZI-BLF53", .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2232100, "CY8C6336BZI-BLD13", .mainfl_kb = 512,   .workfl_kb = 32 
},
+       { 0xE2242100, "CY8C6347BZI-BLD43", .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2252100, "CY8C6347BZI-BLD33", .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2072100, "CY8C6347BZI-BLD53", .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2262100, "CY8C6347FMI-BLD13", .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2272100, "CY8C6347FMI-BLD43", .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2282100, "CY8C6347FMI-BLD33", .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2082100, "CY8C6347FMI-BLD53", .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2011100, "CY8C637BZI-BLD74",  .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2021100, "CY8C637FMI-BLD73",  .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2051100, "CY8C68237BZ-BLE",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2041100, "CY8C68237FM-BLE",   .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0xE2000100, "CY8C622PSVP",       .mainfl_kb = 1024,  .workfl_kb = 32 
},
+       { 0, NULL, 0, 0 },
+};
+
+struct row_region_s safe_sflash_regions[] = {
+       {0x16000800, 0x800},    /* SFLASH: User Data */
+       {0x16001A00, 0x200},    /* SFLASH: NAR */
+       {0x16005A00, 0xC00},    /* SFLASH: Public Key */
+       {0x16007C00, 0x400},    /* SFLASH: TOC2 */
+};
+
+static struct mxs40_chip_info_s *g_current_device;
+static struct working_area *g_stack_area;
+
+/**************************************************************************************************
+ * Initializes timeout_s structure with given timeout in milliseconds
+ 
*************************************************************************************************/
+static void timeout_init(struct timeout_s *to, long timeout_ms)
+{
+       clock_gettime(CLOCK_MONOTONIC, &to->start_time);
+       to->timeout_ms = timeout_ms;
+}
+
+/**************************************************************************************************
+ * Returns true if given timeout_s object has expired
+ 
*************************************************************************************************/
+static int timeout_expired(struct timeout_s *to)
+{
+       struct timespec now_time;
+       struct timespec result;
+
+       clock_gettime(CLOCK_MONOTONIC, &now_time);
+
+       if (now_time.tv_nsec < to->start_time.tv_nsec) {
+               result.tv_sec = now_time.tv_sec - to->start_time.tv_sec - 1;
+               result.tv_nsec = now_time.tv_nsec - to->start_time.tv_nsec + 
1000000000;
+       } else {
+               result.tv_sec = now_time.tv_sec - to->start_time.tv_sec;
+               result.tv_nsec = now_time.tv_nsec - to->start_time.tv_nsec;
+       }
+
+       const long diff_ms = result.tv_sec * 1000 + result.tv_nsec / 1000000;
+       return diff_ms >= to->timeout_ms ? 1 : 0;
+}
+
+/**************************************************************************************************
+ * Acquires PSoC6 device
+ * This function implements so-called 'alternative mode' to acquire the device.
+ *
+ * ARM Vector Catch is not supported by PSoC devices. This is the main reason 
why they can not
+ * be cleanly hated by the debugger. Also, all Flash-related operations 
(includeing probing)
+ * require that target is in Running state. In Cypress proprietary debug 
probes this is achieved
+ * by setting special TEST_MODE bit is short period of time after deasserting 
HW Reset. This is
+ * done by the probe itself by issuing special USB request.
+ * Acquisition procedure is time-critical, all sequence has to be done in less 
than 1 ms after
+ * HW Reset has been deasserted. Third-party debug probes can not enter TEST 
MODE because
+ * of USB latency, etc. Procedure below uses 'alternative' acquisition method 
as described in
+ * "PSoC6 Programming Specification" document.
+ 
*************************************************************************************************/
+static int device_acquire(struct target *tgt)
+{
+       int hr = ERROR_OK;
+       const bool is_cm0 = (tgt->coreid == 0);
+       const struct armv7m_common *cm = target_to_armv7m(tgt);
+
+       /* Read status of CM4 core */
+       uint32_t cm4_ctl;
+       target_read_u32(tgt, 0x40210080, &cm4_ctl);
+
+       /* Reset and enable CM4 core if it is not enabled already */
+       if ((cm4_ctl & 0x03) != 0x03) {
+               hr = target_write_u32(tgt, 0x40210080, 0x05FA0001);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               hr = target_write_u32(tgt, 0x40210080, 0x05FA0003);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       /* Halt target device */
+       if (tgt->state != TARGET_HALTED) {
+               hr = target_halt(tgt);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               target_wait_state(tgt, TARGET_HALTED, IPC_TIMEOUT_MS);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       do {
+               /* Read Vector Offset register */
+               uint32_t vt_base;
+               const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
+               hr = target_read_u32(tgt, vt_offset_reg, &vt_base);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               /* Invalid value means  */
+               vt_base &= 0xFFFFFF00;
+               if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
+                       break;
+
+               uint32_t reset_addr;
+               hr = target_read_u32(tgt, vt_base + 4, &reset_addr);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
+                       break;
+
+               /* Set breakpoint at User Application entry point */
+               hr = breakpoint_add(tgt, reset_addr, 2, BKPT_HARD);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               /* Reset the device by asserting SYSRESETREQ */
+               hr = mem_ap_write_atomic_u32(cm->debug_ap,
+                               NVIC_AIRCR,
+                               AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
+
+               /* Wait for bootcode and initialize DAP */
+               usleep(3000);
+               dap_dp_init(cm->debug_ap->dap);
+
+               /* Remove the break point */
+               breakpoint_remove(tgt, reset_addr);
+
+               if (hr != ERROR_OK)
+                       return hr;
+       } while (0);
+
+       /* Allocate Working Area for RAM Loop and Stack */
+       hr = target_alloc_working_area(tgt, RAM_LOOP_WA_SIZE, &g_stack_area);
+       if (hr != ERROR_OK)
+               return hr;
+
+       const uint32_t wa_addr = g_stack_area->address;
+       const uint32_t wa_size = g_stack_area->size;
+
+       /* Write infinite loop to RAM */
+       hr = target_write_u32(tgt, g_stack_area->address, 0xE7FEE7FE);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       /* Set stack pointer to the end of RAM buffer */
+       hr = cm->store_core_reg_u32(tgt, ARMV7M_R13, wa_addr + wa_size);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       /* Restore THUMB bit in xPSR register */
+       hr = cm->store_core_reg_u32(tgt, ARMV7M_xPSR, 0x01000000);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       /* Start execution of infinite loop */
+       hr = target_resume(tgt, 0, wa_addr, 1, 1);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       return hr;
+
+exit_free_wa:
+       if (g_stack_area) {
+               target_free_working_area(tgt, g_stack_area);
+               g_stack_area = NULL;
+       }
+
+       return hr;
+}
+
+/**************************************************************************************************
+ * Releases acquired device. With 'alternative' acquisition procedure this 
just halts the target.
+ 
*************************************************************************************************/
+static int device_release(struct target *tgt)
+{
+       int hr = target_halt(tgt);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       hr = target_wait_state(tgt, TARGET_HALTED, IPC_TIMEOUT_MS);
+
+exit_free_wa:
+       if (g_stack_area) {
+               target_free_working_area(tgt, g_stack_area);
+               g_stack_area = NULL;
+       }
+
+       return hr;
+}
+
+/**************************************************************************************************
+ * Waits for expected IPC lock status.
+ * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used 
to invoke SROM API.
+ * IPC structure must be locked prior to invoking any SROM API. This ensures 
nothing else in the
+ * system will use same IPC thus corrupting our data. Locking is performed by 
ipc_acquire(), this
+ * function ensures that IPC is actually in expected state
+ 
*************************************************************************************************/
+static int ipc_poll_lock_stat(struct target *tgt, uint32_t ipc_id, bool 
lock_expected)
+{
+       int hr;
+       uint32_t reg_val;
+
+       struct timeout_s to;
+       timeout_init(&to, IPC_TIMEOUT_MS);
+
+       while (!timeout_expired(&to)) {
+               /* Process any server requests */
+               keep_alive();
+
+               /* Read IPC Lock status */
+               hr = target_read_u32(tgt, MEM_IPC_LOCK_STATUS(ipc_id), 
&reg_val);
+               if (hr != ERROR_OK) {
+                       LOG_ERROR("Unable to read IPC Lock Status register");
+                       return hr;
+               }
+
+               bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
+               bool is_status_expected = !!lock_expected == !!is_locked;
+
+               if (is_status_expected)
+                       return ERROR_OK;
+       }
+
+       LOG_ERROR("Timeout polling IPC Lock Status");
+       return ERROR_TARGET_TIMEOUT;
+}
+
+/**************************************************************************************************
+ * Acquires IPC structure
+ * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used 
to invoke SROM API.
+ * IPC structure must be locked prior to invoking any SROM API. This ensures 
nothing else in the
+ * system will use same IPC thus corrupting our data. This function locks the 
IPC.
+ 
*************************************************************************************************/
+static int ipc_acquire(struct target *tgt, char ipc_id)
+{
+       int hr = ERROR_OK;
+       bool is_acquired;
+       uint32_t reg_val;
+
+       struct timeout_s to;
+       timeout_init(&to, IPC_TIMEOUT_MS);
+
+       while (!timeout_expired(&to)) {
+               keep_alive();
+
+               hr = target_write_u32(tgt, MEM_IPC_ACQUIRE(ipc_id), 
IPC_ACQUIRE_SUCCESS_MSK);
+               if (hr != ERROR_OK) {
+                       LOG_ERROR("Unable to write to IPC Acquire register");
+                       return hr;
+               }
+
+               /* Check if data is writen on first step */
+               hr = target_read_u32(tgt, MEM_IPC_ACQUIRE(ipc_id), &reg_val);
+               if (hr != ERROR_OK) {
+                       LOG_ERROR("Unable to read IPC Acquire register");
+                       return hr;
+               }
+
+               is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
+               if (is_acquired)
+                       return ERROR_OK;
+       }
+
+       if (!is_acquired) {
+               LOG_ERROR("Timeout acquiring IPC structure");
+               return ERROR_TARGET_TIMEOUT;
+       }
+
+       /* If IPC structure is acquired, the lock status should be set */
+       hr = ipc_poll_lock_stat(tgt, ipc_id, true);
+       return hr;
+}
+
+/**************************************************************************************************
+ * Invokes SROM API functions which are responsible for Flash operations
+ 
*************************************************************************************************/
+static int call_sromapi(struct target *tgt,
+       uint32_t req_and_params,
+       uint32_t working_area,
+       uint32_t *dataOut)
+{
+       int hr;
+
+       bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
+
+       hr = ipc_acquire(tgt, IPC_ID);
+       if (hr != ERROR_OK)
+               return hr;
+
+       if (is_data_in_ram)
+               target_write_u32(tgt, MEM_IPC_DATA(IPC_ID), working_area);
+       else
+               target_write_u32(tgt, MEM_IPC_DATA(IPC_ID), req_and_params);
+
+       /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for 
IPC_STRUCT2 */
+       target_write_u32(tgt, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + 
IPC_ID));
+
+       /* Notify to IPC_INTR_STRUCT0. IPC_STRUCT2.MASK <- Notify */
+       target_write_u32(tgt, MEM_IPC_NOTIFY(IPC_ID), 1);
+
+       /* Poll lock status */
+       hr = ipc_poll_lock_stat(tgt, IPC_ID, false);
+       if (hr != ERROR_OK)
+               return hr;
+
+       /* Poll Data byte */
+       if (is_data_in_ram)
+               hr = target_read_u32(tgt, working_area, dataOut);
+       else
+               hr = target_read_u32(tgt, MEM_IPC_DATA(IPC_ID), dataOut);
+
+       if (hr != ERROR_OK) {
+               LOG_ERROR("Error reading SROM API Status location");
+               return hr;
+       }
+
+       bool is_success = (*dataOut & SROMAPI_STATUS_MSK) == 
SROMAPI_STAT_SUCCESS;
+       if (!is_success) {
+               LOG_ERROR("SROM API execution failed. Status: 0x%08X", 
(uint32_t)*dataOut);
+               return ERROR_TARGET_FAILURE;
+       }
+
+       return ERROR_OK;
+}
+
+/**************************************************************************************************
+ * Retrieves SiliconID and Protection status of the target device
+ 
*************************************************************************************************/
+static int get_silicon_id(struct target *tgt, uint32_t *si_id, uint8_t 
*protection)
+{
+       int hr;
+       uint32_t family_rev, siid_prot;
+
+       /* Read FamilyID and Revision */
+       hr = call_sromapi(tgt, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, 
&family_rev);
+       if (hr != ERROR_OK)
+               return hr;
+
+       /* Read SiliconID and Protection */
+       hr = call_sromapi(tgt, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
+       if (hr != ERROR_OK)
+               return hr;
+
+       *si_id  = (siid_prot & 0x0000FFFF) << 16;
+       *si_id |= (family_rev & 0x00FF0000) >> 8;
+       *si_id |= (family_rev & 0x000000FF) >> 0;
+
+       *protection = (siid_prot & 0x000F0000) >> 0x10;
+
+       return ERROR_OK;
+}
+
+/**************************************************************************************************
+ * Translates Protection status to openocd-friendly boolean value
+ 
*************************************************************************************************/
+static int psoc6_protect_check(struct flash_bank *bank)
+{
+       int is_protected;
+
+       struct psoc6_target_info_s *psoc6_info = bank->driver_priv;
+       switch (psoc6_info->protection) {
+               case PROTECTION_VIRGIN:
+               case PROTECTION_NORMAL:
+                       is_protected = 0;
+                       break;
+
+               case PROTECTION_UNKNOWN:
+               case PROTECTION_SECURE:
+               case PROTECTION_DEAD:
+               default:
+                       is_protected = 1;
+                       break;
+       }
+
+       for (int i = 0; i < bank->num_sectors; i++)
+               bank->sectors[i].is_protected = is_protected;
+
+       return ERROR_OK;
+}
+
+/**************************************************************************************************
+ * Lifecycle transition is not currently supported
+ 
*************************************************************************************************/
+static int psoc6_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       (void)bank;
+       (void)set;
+       (void)first;
+       (void)last;
+
+       LOG_WARNING("Lifecycle transition for PSoC6 is not supported");
+       return ERROR_OK;
+}
+
+/**************************************************************************************************
+ * Translates Protection status to string
+ 
*************************************************************************************************/
+static const char *protection_to_str(uint8_t protection)
+{
+       switch (protection) {
+               case PROTECTION_VIRGIN:
+                       return "VIRGIN";
+                       break;
+               case PROTECTION_NORMAL:
+                       return "NORMAL";
+                       break;
+               case PROTECTION_SECURE:
+                       return "SECURE";
+                       break;
+               case PROTECTION_DEAD:
+                       return "DEAD";
+                       break;
+               case PROTECTION_UNKNOWN:
+               default:
+                       return "UNKNOWN";
+                       break;
+       }
+}
+
+/**************************************************************************************************
+ * Displays human-readable information about acquired device
+ 
*************************************************************************************************/
+static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct psoc6_target_info_s *psoc6_info = bank->driver_priv;
+
+       if (psoc6_info->is_probed == 0)
+               return ERROR_FAIL;
+
+       snprintf(buf, buf_size,
+               "Detected device: %s, Silicon ID: 0x%08X\n" \
+               "Protection: %s\n"
+               "Main Flash size: %d kB\n" \
+               "Work Flash size: %d kB\n",
+               g_current_device->mpn_str,
+               g_current_device->silicon_id,
+               protection_to_str(psoc6_info->protection),
+               g_current_device->mainfl_kb,
+               g_current_device->workfl_kb);
+
+       return ERROR_OK;
+}
+
+
+/**************************************************************************************************
+ * Probes the device and populates related data structures with target flash 
geometry data
+ 
*************************************************************************************************/
+static int psoc6_probe(struct flash_bank *bank)
+{
+       struct target *tgt = bank->target;
+       struct psoc6_target_info_s *psoc6_info = bank->driver_priv;
+
+       int hr = ERROR_OK;
+
+       static uint32_t g_silicon_id;
+       static uint8_t g_protection;
+
+       if (g_silicon_id == 0 && bank->target->coreid != 0) {
+               LOG_ERROR("Please attach to CM0 core first!");
+               return ERROR_FAIL;
+       }
+
+       if (bank->target->coreid == 0) {
+               hr = device_acquire(tgt);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               hr = get_silicon_id(tgt, &g_silicon_id, &g_protection);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       psoc6_info->protection = g_protection;
+       psoc6_info->silicon_id = g_silicon_id;
+
+       g_current_device = &psoc6_devices[0];
+       while (g_current_device->silicon_id) {
+               if (g_current_device->silicon_id == g_silicon_id)
+                       break;
+               g_current_device++;
+       }
+
+       if (g_current_device->silicon_id == 0) {
+               LOG_ERROR("Unknown PSoC6 device! SiliconID = 0x%08X", 
g_silicon_id);
+               return ERROR_TARGET_INVALID;
+       }
+
+       LOG_DEBUG("Detected device: %s, SiliconID: 0x%08X, Flash Bank: %s",
+               g_current_device->mpn_str,
+               g_current_device->silicon_id,
+               bank->name);
+
+       if (bank->sectors) {
+               free(bank->sectors);
+               bank->sectors = NULL;
+       }
+
+       uint32_t base_addr;
+       size_t bank_size;
+
+       if (strstr(bank->name, "main_flash") == bank->name) {
+               base_addr = MEM_BASE_MFLASH;
+               bank_size = 1024 * g_current_device->mainfl_kb;
+       } else if (strstr(bank->name, "work_flash") == bank->name) {
+               base_addr = MEM_BASE_WFLASH;
+               bank_size = 1024 * g_current_device->workfl_kb;
+       } else if (strstr(bank->name, "super_flash_user") == bank->name) {
+               base_addr = safe_sflash_regions[SFLASH_USER_INDEX].addr;
+               bank_size = safe_sflash_regions[SFLASH_USER_INDEX].size;
+       } else if (strstr(bank->name, "super_flash_nar") == bank->name) {
+               base_addr = safe_sflash_regions[SFLASH_NAR_INDEX].addr;
+               bank_size = safe_sflash_regions[SFLASH_NAR_INDEX].size;
+       } else if (strstr(bank->name, "super_flash_key") == bank->name) {
+               base_addr = safe_sflash_regions[SFLASH_KEY_INDEX].addr;
+               bank_size = safe_sflash_regions[SFLASH_KEY_INDEX].size;
+       } else if (strstr(bank->name, "super_flash_toc2") == bank->name) {
+               base_addr = safe_sflash_regions[SFLASH_TOC2_INDEX].addr;
+               bank_size = safe_sflash_regions[SFLASH_TOC2_INDEX].size;
+       } else {
+               LOG_ERROR("Unknown flash type given, should be 'main_flash', 
'work_flash', 'super_flash_user', "
+                       "'super_flash_nar', 'super_flash_key' or 
'super_flash_toc2' suffixed by '_cm0' or '_cm4'");
+
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       size_t num_sectors = bank_size / FLASH_ROW_SIZE;
+       bank->base = base_addr;
+       bank->size = bank_size;
+       bank->chip_width = 4;
+       bank->bus_width = 4;
+       bank->erased_value = 0;
+       bank->default_padded_value = 0;
+
+       bank->num_sectors = num_sectors;
+       bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
+       for (size_t i = 0; i < num_sectors; i++) {
+               bank->sectors[i].size = FLASH_ROW_SIZE;
+               bank->sectors[i].offset = i * FLASH_ROW_SIZE;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = -1;
+       }
+
+       if (bank->target->coreid == 0)
+               hr = device_release(tgt);
+
+       psoc6_info->is_probed = 1;
+
+       return hr;
+}
+
+/**************************************************************************************************
+ * Probes target device only if it hasnt been probed yet
+ 
*************************************************************************************************/
+static int psoc6_auto_probe(struct flash_bank *bank)
+{
+       struct psoc6_target_info_s *psoc6_info = bank->driver_priv;
+       int hr;
+
+       if (psoc6_info->is_probed)
+               hr = ERROR_OK;
+       else
+               hr = psoc6_probe(bank);
+
+       return hr;
+}
+
+/**************************************************************************************************
+ * Returns true if flash bank name represents Supervisory Flash
+ 
*************************************************************************************************/
+static bool is_sflash_bank(struct flash_bank *bank)
+{
+       const bool is_sflash = (strstr(bank->name, "super_flash_user") == 
bank->name) || \
+               (strstr(bank->name, "super_flash_nar") == bank->name) || \
+               (strstr(bank->name, "super_flash_key") == bank->name) || \
+               (strstr(bank->name, "super_flash_toc2") == bank->name);
+
+       return is_sflash;
+}
+
+/**************************************************************************************************
+ * Erases set of sectors on target device
+ 
*************************************************************************************************/
+static int psoc6_erase_sectors(struct flash_bank *bank, int first, int last)
+{
+       struct target *tgt = bank->target;
+       int hr;
+       struct working_area *wa;
+
+       if (is_sflash_bank(bank)) {
+               LOG_INFO("Erase operation on Supervisory Flash is not required, 
skipping");
+               return ERROR_OK;
+       }
+
+       hr = device_acquire(tgt);
+       if (hr != ERROR_OK)
+               return hr;
+
+       hr = target_alloc_working_area(tgt, FLASH_ROW_SIZE + 32, &wa);
+       if (hr != ERROR_OK)
+               goto exit;
+
+       while (((first % FLASH_ROW_SIZE) == 0) &&
+               ((last - first + 1) >= (int)FLASH_NUM_ROWS_IN_SECTOR)) {
+               uint32_t addr = bank->base + first * bank->sectors[0].size;
+               LOG_DEBUG("Erasing flash SECTOR '%s' @0x%08X", bank->name, 
addr);
+
+               hr = target_write_u32(tgt, wa->address, 
SROMAPI_ERASESECTOR_REQ);
+               if (hr != ERROR_OK)
+                       goto exit_free_wa;
+
+               hr = target_write_u32(tgt, wa->address + 0x04, addr);
+               if (hr != ERROR_OK)
+                       goto exit_free_wa;
+
+               uint32_t dataOut;
+               hr = call_sromapi(tgt, SROMAPI_ERASESECTOR_REQ, wa->address, 
&dataOut);
+               if (hr != ERROR_OK) {
+                       LOG_ERROR("Sector \"%d\" not erased!", first / 
FLASH_NUM_ROWS_IN_SECTOR);
+                       goto exit_free_wa;
+               }
+
+               first += FLASH_NUM_ROWS_IN_SECTOR;
+       }
+
+       for (int i = first; i <= last; i++) {
+               uint32_t addr = bank->base + i * bank->sectors[0].size;
+               LOG_DEBUG("Erasing flash ROW '%s' @0x%08X", bank->name, addr);
+
+               hr = target_write_u32(tgt, wa->address, SROMAPI_ERASEROW_REQ);
+               if (hr != ERROR_OK)
+                       goto exit_free_wa;
+
+               hr = target_write_u32(tgt, wa->address + 0x04, addr);
+               if (hr != ERROR_OK)
+                       goto exit_free_wa;
+
+               uint32_t dataOut;
+               hr = call_sromapi(tgt, SROMAPI_ERASEROW_REQ, wa->address, 
&dataOut);
+               if (hr != ERROR_OK) {
+                       LOG_ERROR("Row \"%d\" not erased!", i);
+                       goto exit_free_wa;
+               }
+       }
+
+exit_free_wa:
+       target_free_working_area(tgt, wa);
+exit:
+       device_release(tgt);
+
+       return hr;
+}
+
+
+/**************************************************************************************************
+ * Programs single Flash Row
+ 
*************************************************************************************************/
+static int psoc6_program_row(struct target *tgt,
+       uint32_t addr,
+       const uint8_t *buffer,
+       uint32_t count,
+       bool is_sflash)
+{
+       struct working_area *wa;
+       const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : 
SROMAPI_PROGRAMROW_REQ;
+       uint32_t dataOut;
+       int hr = ERROR_OK;
+
+       hr = target_alloc_working_area(tgt, FLASH_ROW_SIZE + 32, &wa);
+       if (hr != ERROR_OK)
+               goto exit;
+
+       hr = target_write_u32(tgt, wa->address, sromapi_req);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       hr = target_write_u32(tgt,
+                       wa->address + 0x04,
+                       0x106);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       hr = target_write_u32(tgt, wa->address + 0x08, addr);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       hr = target_write_u32(tgt, wa->address + 0x0C, wa->address + 0x10);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       hr = target_write_buffer(tgt, wa->address + 0x10, count, buffer);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       hr = call_sromapi(tgt, sromapi_req, wa->address, &dataOut);
+
+exit_free_wa:
+       target_free_working_area(tgt, wa);
+
+exit:
+       return hr;
+}
+
+
+/**************************************************************************************************
+ * Programs set of Rows
+ 
*************************************************************************************************/
+static int psoc6_program(struct flash_bank *bank,
+       const uint8_t *buffer,
+       uint32_t offset,
+       uint32_t count)
+{
+       struct target *target = bank->target;
+       const bool is_sflash = is_sflash_bank(bank);
+       int hr;
+
+       hr = device_acquire(target);
+       if (hr != ERROR_OK)
+               return hr;
+
+       uint32_t remaining = count;
+       uint8_t page_buf[FLASH_ROW_SIZE];
+       uint32_t addr, size, sourceOffset, maxAdressSize;
+
+       sourceOffset = 0;
+       addr = bank->base + offset;
+       maxAdressSize = (addr + count);
+       while (addr < maxAdressSize) {
+               LOG_DEBUG("Writing data to 0x%08X ...", addr);
+
+               size = FLASH_ROW_SIZE;
+               if (remaining < FLASH_ROW_SIZE) {
+                       memset(page_buf, 0x00, size);
+                       memcpy(page_buf, &buffer[sourceOffset], remaining);
+                       size = remaining;
+               } else
+                       memcpy(page_buf, &buffer[sourceOffset], size);
+
+               hr = psoc6_program_row(target, addr, page_buf, size, is_sflash);
+               if (hr != ERROR_OK) {
+                       LOG_ERROR("Failed to program Flash at address 0x%08X", 
addr);
+                       break;
+               }
+
+               sourceOffset += size;
+               addr = addr + size;
+               remaining -= size;
+       }
+
+       hr = device_release(target);
+       return hr;
+}
+
+/**************************************************************************************************
+ * Performs Mass Erase of Main Flash region
+ 
*************************************************************************************************/
+COMMAND_HANDLER(psoc6_handle_mass_erase_command)
+{
+       if (CMD_ARGC)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct target *tgt = get_current_target(CMD_CTX);
+       struct working_area *wa;
+       uint32_t dataOut;
+       int hr;
+
+       command_print(CMD_CTX, "Performing Mass Erase...");
+       hr = device_acquire(tgt);
+       if (hr != ERROR_OK)
+               goto exit;
+
+       hr = target_alloc_working_area(tgt, FLASH_ROW_SIZE + 32, &wa);
+       if (hr != ERROR_OK)
+               goto exit;
+
+       hr = target_write_u32(tgt, wa->address, SROMAPI_ERASEALL_REQ);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+       hr = call_sromapi(tgt, SROMAPI_ERASEALL_REQ, wa->address, &dataOut);
+       if (hr != ERROR_OK)
+               goto exit_free_wa;
+
+exit_free_wa:
+       if (hr == ERROR_OK)
+               command_print(CMD_CTX, "Success!");
+       else
+               command_print(CMD_CTX, "Fail!");
+
+       device_release(tgt);
+       target_free_working_area(tgt, wa);
+
+exit:
+       return hr;
+}
+
+FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
+{
+       struct psoc6_target_info_s *psoc6_info;
+       int hr = ERROR_OK;
+
+       if (CMD_ARGC < 6)
+               hr = ERROR_COMMAND_SYNTAX_ERROR;
+       else {
+               psoc6_info = calloc(1, sizeof(struct psoc6_target_info_s));
+
+               psoc6_info->info = g_current_device;
+               psoc6_info->is_probed = 0;
+               bank->driver_priv = psoc6_info;
+       }
+       return hr;
+}
+
+static const struct command_registration psoc6_exec_command_handlers[] = {
+       {
+               .name = "mass_erase",
+               .handler = psoc6_handle_mass_erase_command,
+               .mode = COMMAND_EXEC,
+               .usage = NULL,
+               .help = "Erase entire Main Flash",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration psoc6_command_handlers[] = {
+       {
+               .name = "psoc6",
+               .mode = COMMAND_ANY,
+               .help = "PSoC 6 flash command group",
+               .usage = "",
+               .chain = psoc6_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver psoc6_flash = {
+       .name = "psoc6",
+       .commands = psoc6_command_handlers,
+       .flash_bank_command = psoc6_flash_bank_command,
+       .erase = psoc6_erase_sectors,
+       .protect = psoc6_protect,
+       .write = psoc6_program,
+       .read = default_flash_read,
+       .probe = psoc6_probe,
+       .auto_probe = psoc6_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = psoc6_protect_check,
+       .info = psoc6_get_info,
+};
diff --git a/tcl/target/psoc6.cfg b/tcl/target/psoc6.cfg
new file mode 100644
index 0000000..cfb3963
--- /dev/null
+++ b/tcl/target/psoc6.cfg
@@ -0,0 +1,87 @@
+source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
+
+adapter_khz 1000
+
+global _CHIPNAME
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME psoc6
+}
+
+global TARGET
+set TARGET $_CHIPNAME.cpu
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf
+
+# Is CM0 Debugging enabled ?
+global _ENABLE_CM0
+if { [info exists ENABLE_CM0] } {
+   set _ENABLE_CM0 $ENABLE_CM0
+} else {
+   set _ENABLE_CM0 1
+}
+
+# Is CM4 Debugging enabled ?
+global _ENABLE_CM4
+if { [info exists ENABLE_CM4] } {
+   set _ENABLE_CM4 $ENABLE_CM4
+} else {
+   set _ENABLE_CM4 1
+}
+
+global _WORKAREASIZE_CM0
+if { [info exists WORKAREASIZE_CM0] } {
+   set _WORKAREASIZE_CM0 $WORKAREASIZE_CM0
+} else {
+   set _WORKAREASIZE_CM0 0x4000
+}
+
+global _WORKAREASIZE_CM4
+if { [info exists WORKAREASIZE_CM4] } {
+   set _WORKAREASIZE_CM4 $WORKAREASIZE_CM4
+} else {
+   set _WORKAREASIZE_CM4 0x4000
+}
+
+global _WORKAREAADDR_CM0
+if { [info exists WORKAREAADDR_CM0] } {
+   set _WORKAREAADDR_CM0 $WORKAREAADDR_CM0
+} else {
+   set _WORKAREAADDR_CM0 0x08000000
+}
+
+global _WORKAREAADDR_CM4
+if { [info exists WORKAREAADDR_CM4] } {
+   set _WORKAREAADDR_CM4 $WORKAREAADDR_CM4
+} else {
+   set _WORKAREAADDR_CM4 0x08000000
+}
+
+if { $_ENABLE_CM0 } {
+       target create ${TARGET}.cm0 cortex_m -chain-position $TARGET -ap-num 1 
-coreid 0
+       ${TARGET}.cm0 configure -work-area-phys $_WORKAREAADDR_CM0 
-work-area-size $_WORKAREASIZE_CM0 -work-area-backup 0
+
+       flash bank main_flash_cm0               psoc6 0x00000000 0 0 0 
${TARGET}.cm0
+       flash bank work_flash_cm0               psoc6 0x00000000 0 0 0 
${TARGET}.cm0
+       flash bank super_flash_user_cm0 psoc6 0x00000000 0 0 0 ${TARGET}.cm0
+       flash bank super_flash_nar_cm0  psoc6 0x00000000 0 0 0 ${TARGET}.cm0
+       flash bank super_flash_key_cm0  psoc6 0x00000000 0 0 0 ${TARGET}.cm0
+       flash bank super_flash_toc2_cm0 psoc6 0x00000000 0 0 0 ${TARGET}.cm0
+}
+
+if { $_ENABLE_CM4 } {
+       target create ${TARGET}.cm4 cortex_m -chain-position $TARGET -ap-num 2 
-coreid 1
+       ${TARGET}.cm4 configure -work-area-phys $_WORKAREAADDR_CM4 
-work-area-size $_WORKAREASIZE_CM4 -work-area-backup 0
+
+       flash bank main_flash_cm4               psoc6 0x00000000 0 0 0 
${TARGET}.cm4
+       flash bank work_flash_cm4               psoc6 0x00000000 0 0 0 
${TARGET}.cm4
+       flash bank super_flash_user_cm4 psoc6 0x00000000 0 0 0 ${TARGET}.cm4
+       flash bank super_flash_nar_cm4  psoc6 0x00000000 0 0 0 ${TARGET}.cm4
+       flash bank super_flash_key_cm4  psoc6 0x00000000 0 0 0 ${TARGET}.cm4
+       flash bank super_flash_toc2_cm4 psoc6 0x00000000 0 0 0 ${TARGET}.cm4
+}
+
+targets ${TARGET}.cm0
+cortex_m reset_config srst_and_trst srst_pulls_trst

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to