This is an automated email from Gerrit.

"Name of user not set <r.nooteb...@gmail.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7983

-- gerrit

commit 1aad736f824cb52f597b07676a4645d4675e0b37
Author: RolfNoot <r.nooteb...@gmail.com>
Date:   Sun Dec 10 21:23:57 2023 +0100

    update PSoC6 flash driver
    
    95% based on latest Infineon branch (5.0.0)
    
    removed exotic silicons and ballast
    
    original sources are scattered over multiple files
    
    converted in one solid driver for PSoC6
    
    creditss to Bohdan Tymkiv
    
    Change-Id: Iab952e58e7e4fa4c768a1cf51dfa8bbf53c43243
    Signed-off-by: RolfNoot <r.nooteb...@gmail.com>

diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c
index b7ba1027ed..27564bffd5 100644
--- a/src/flash/nor/psoc6.c
+++ b/src/flash/nor/psoc6.c
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 /***************************************************************************
+ *   Copyright (C) 2023 by Rolf Nooteboom                                  *
+ *   r.nooteb...@gmail.com                                                 *
  *                                                                         *
  *   Copyright (C) 2018 by Bohdan Tymkiv                                   *
  *   bohdan.tym...@cypress.com bohdan...@gmail.com                         *
@@ -10,134 +12,383 @@
 #include "config.h"
 #endif
 
-#include <time.h>
-
 #include "imp.h"
 #include "helper/time_support.h"
+#include "target/algorithm.h"
 #include "target/arm_adi_v5.h"
-#include "target/target.h"
-#include "target/cortex_m.h"
 #include "target/breakpoints.h"
-#include "target/target_type.h"
-#include "target/algorithm.h"
+#include "target/cortex_m.h"
+#include "target/image.h"
+#include "target/register.h"
+#include "target/target.h"
+#include "rtos/rtos.h"
 
 
/**************************************************************************************************
  * PSoC6 device definitions
  
*************************************************************************************************/
-#define MFLASH_SECTOR_SIZE              (256u * 1024u)
-#define WFLASH_SECTOR_SIZE              (32u * 1024u)
-
-#define MEM_BASE_MFLASH                 0x10000000u
-#define MEM_BASE_WFLASH                 0x14000000u
-#define MEM_WFLASH_SIZE                 32768u
-#define MEM_BASE_SFLASH                 0x16000000u
-#define RAM_STACK_WA_SIZE               2048u
-#define PSOC6_SPCIF_GEOMETRY            0x4025F00Cu
-
-#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
-#define SROMAPI_CALL_TIMEOUT_MS             1500
-
-struct psoc6_target_info {
-       uint32_t silicon_id;
-       uint8_t protection;
-       uint32_t main_flash_sz;
-       uint32_t row_sz;
+#define k_b(x)                                                         ((x) << 
10u)
+#define m_b(x)                                                         ((x) << 
20u)
+
+#define MFLASH_SECTOR_SIZE_256K                                k_b(256u)
+#define MFLASH_SECTOR_SIZE_128K                                k_b(128u)
+#define WFLASH_SECTOR_SIZE                                     k_b(32u)
+
+#define MEM_WFLASH_SIZE                                                32768u
+#define MEM_SFLASH_SIZE                                                32768u
+
+#define RAM_STACK_WA_SIZE                                      2048u
+
+#define MEM_SPCIF1_GEOMETRY                                    0x4025F00Cu
+#define MEM_BASE_IPC1                                          0x40230040u
+#define MEM_IPC1_INTR_MASK                                     0x40231008u
+#define MEM_VTBASE1_CM0                                                
0x402102B0u
+#define MEM_VTBASE1_CM4                                                
0x402102C0u
+#define MEM_IPC1_ACQUIRE                                       (MEM_BASE_IPC1 
+ 0x00u)
+#define MEM_IPC1_RELEASE                                       (MEM_BASE_IPC1 
+ 0x04u)
+#define MEM_IPC1_NOTIFY                                                
(MEM_BASE_IPC1 + 0x08u)
+#define MEM_IPC1_DATA                                          (MEM_BASE_IPC1 
+ 0x0Cu)
+#define MEM_IPC1_LOCK_STATUS                           (MEM_BASE_IPC1 + 0x10u)
+
+#define MEM_SPCIF2_GEOMETRY                                    0x4024F010u
+#define MEM_SPCIF3_GEOMETRY                                    0x4024F00Cu
+#define MEM_BASE_IPC2                                          0x40220060u
+#define MEM_IPC2_INTR_MASK                                     0x40221008u
+#define MEM_VTBASE2_CM0                                                
0x40201120u
+#define MEM_VTBASE2_CM4                                                
0x40200200u
+#define MEM_IPC2_ACQUIRE                                       (MEM_BASE_IPC2 
+ 0x00u)
+#define MEM_IPC2_RELEASE                                       (MEM_BASE_IPC2 
+ 0x04u)
+#define MEM_IPC2_NOTIFY                                                
(MEM_BASE_IPC2 + 0x08u)
+#define MEM_IPC2_DATA                                          (MEM_BASE_IPC2 
+ 0x0Cu)
+#define MEM_IPC2_LOCK_STATUS                           (MEM_BASE_IPC2 + 0x1Cu)
+
+#define IPC_INTR_MASK_1_CORE                           (0x02u << 16u)
+#define IPC_INTR_MASK_2_CORE                           (0x04u << 16u)
+#define IPC_INTR_MASK_3_CORE                           (0x08u << 16u)
+
+#define IPC_ACQUIRE_SUCCESS_MSK                                0x80000000u
+#define IPC_LOCK_ACQUIRED_MSK                          0x80000000u
+
+#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_READ_FUSE_BYTE                         0x03000001u
+#define SROMAPI_CHECK_FACTORY_HASH                     0x27000001u
+#define SROMAPI_GENERATE_HASH_CODE                     0x1E000000u
+
+#define SROMAPI_STATUS_MSK                                     0xF0000000u
+#define SROMAPI_STAT_SUCCESS                           0xA0000000u
+#define SROMAPI_DATA_LOCATION_MSK                      0x00000001u
+#define IPC_TIMEOUT_MS                                         1500
+#define CM0_VTOR_TIMEOUT_MS                                    600
+#define OTHER_VTOR_TIMEOUT_MS                          10000
+
+#define FLASH_CONTROLLER_1_MSK                         0x08000000u
+
+#define SROMAPI_PROGRAMROW0_REQ                                0x06000100u
+#define SROMAPI_ERASESECTOR0_REQ                       0x14000100u
+#define SROMAPI_PROGRAMROW1_REQ                                0x09000100u
+#define SROMAPI_ERASESECTOR1_REQ                       0x1C000100u
+
+#define PSOC6_VARIANT_PSOC6_BLE2                       1
+#define PSOC6_VARIANT_PSOC6A_2M                                2
+
+#define CHIP_PROT_UNKNOWN                                      0x00u
+#define CHIP_PROT_VIRGIN                                       0x01u
+#define CHIP_PROT_NORMAL                                       0x02u
+#define CHIP_PROT_SECURE                                       0x03u
+#define CHIP_PROT_DEAD                                         0x04u
+#define CHIP_PROT_MASK                                         0x0Fu
+
+#define NVIC_VTOR                                                      
0xE000ED08
+
+enum reset_halt_mode {
+       mode_default,
+       mode_sysresetreq,
+       mode_vectreset
+};
+
+struct bank_match {
+       uint32_t address_mask;
+       uint32_t address_value;
+};
+
+#define BANK_MATCH_END {0, 0}
+
+struct psoc6_regs {
+       uint32_t variant;
+       uint32_t ipc_acquire;
+       uint32_t ipc_notify;
+       uint32_t ipc_data;
+       uint32_t ipc_lock_stat;
+       uint32_t ipc_intr;
+       uint32_t ipc_intr_msk;
+       uint32_t ppu_flush;
+       uint32_t vtbase[3];
+       struct bank_match mem_base_main[5];
+       struct bank_match mem_base_work[5];
+       struct bank_match mem_base_sflash[5];
+};
+
+// defines efuse regions that are programmed in a special way
+struct efuse_regions {
+       uint32_t        lifecycle_offset;
+       uint32_t        lifecycle_size;
+       uint32_t        dead_access_offset;
+       uint32_t        dead_access_size;
+       uint32_t        secure_access_offset;
+       uint32_t        secure_access_size;
+};
+
+struct sflash_region {
+       uint32_t addr;
+       uint32_t size;
+       uint8_t flags;
+};
+
+struct psoc6_bank_info {
        bool is_probed;
+       bool ppu_read_protected;
+       bool has_erase_subsector_bug;
+       uint32_t size_override;
+       uint32_t page_size;
+       size_t program_algo_size;
+       size_t erase_algo_size;
+       const uint8_t *program_algo_p;
+       const uint8_t *erase_algo_p;
+       const struct psoc6_regs *regs;
+       const struct efuse_regions *efuse_regions;
+       const struct sflash_region *sflash_regions;
+       int (*prepare_function)(struct flash_bank *bank);
 };
 
+
 struct timeout {
        int64_t start_time;
        long timeout_ms;
 };
 
 struct row_region {
-       uint32_t addr;
-       size_t size;
+       char *target_name;
+       target_addr_t addr;
+       uint32_t size;
+};
+
+typedef size_t (*erase_builder)(struct flash_bank *bank, int first, int last, 
uint32_t *address_buffer);
+
+/* PSOC6A1M registers */
+const struct psoc6_regs psoc6_ble2_regs = {
+       .variant = PSOC6_VARIANT_PSOC6_BLE2,
+       .ipc_acquire = MEM_IPC1_ACQUIRE,
+       .ipc_notify = MEM_IPC1_NOTIFY,
+       .ipc_data = MEM_IPC1_DATA,
+       .ipc_lock_stat = MEM_IPC1_LOCK_STATUS,
+       .ipc_intr = MEM_IPC1_INTR_MASK,
+       .ipc_intr_msk = IPC_INTR_MASK_2_CORE,
+       .vtbase = { MEM_VTBASE1_CM0, MEM_VTBASE1_CM4, 0, },
+       .mem_base_main = {
+               {0xFF000000, 0x10000000},
+               BANK_MATCH_END
+       },
+       .mem_base_work = {
+               {0xFF000000, 0x14000000},
+               BANK_MATCH_END
+       },
+       .mem_base_sflash = {
+               {0xFF000000, 0x16000000},
+               BANK_MATCH_END
+       },
 };
 
-static const struct row_region safe_sflash_regions[] = {
-       {0x16000800, 0x800},    /* SFLASH: User Data */
-       {0x16001A00, 0x200},    /* SFLASH: NAR */
-       {0x16005A00, 0xC00},    /* SFLASH: Public Key */
-       {0x16007C00, 0x400},    /* SFLASH: TOC2 */
+/* PSoC6A2M registers */
+const struct psoc6_regs psoc6_2m_regs = {
+       .variant = PSOC6_VARIANT_PSOC6A_2M,
+       .ipc_acquire = MEM_IPC2_ACQUIRE,
+       .ipc_notify = MEM_IPC2_NOTIFY,
+       .ipc_data = MEM_IPC2_DATA,
+       .ipc_lock_stat = MEM_IPC2_LOCK_STATUS,
+       .ipc_intr = MEM_IPC2_INTR_MASK,
+       .ipc_intr_msk = IPC_INTR_MASK_2_CORE,
+       .ppu_flush = 0x40010100,
+       .vtbase = { MEM_VTBASE2_CM0, MEM_VTBASE2_CM4, 0, },
+       .mem_base_main = {
+               {0xFF000000, 0x10000000},
+               BANK_MATCH_END
+       },
+       .mem_base_work = {
+               {0xFF000000, 0x14000000},
+               BANK_MATCH_END
+       },
+       .mem_base_sflash = {
+               {0xFF000000, 0x16000000},
+               BANK_MATCH_END
+       },
+
 };
 
-#define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
+// Define SFlash layout (USER, TOC2, NAR, KEY)
+// All regions must have '0xEE' attribute except NAR - '0xC0'
+static const struct sflash_region psoc6_safe_sflash_regions[4] = {
+       {0x16000800, 0x800, 0xEE},
+       {0x16001A00, 0x200, 0xC0},
+       {0x16005A00, 0xC00, 0xEE},
+       {0x16007C00, 0x400, 0xEE},
+};
 
 static struct working_area *g_stack_area;
 static struct armv7m_algorithm g_armv7m_info;
+static uint32_t g_sflash_restrictions;
+static bool g_sromcall_prepare_called;
+
+enum operation {
+       PROGRAM,
+       ERASE
+};
+
+/** 
***********************************************************************************************
+ * @brief Iterates over all flash banks, locates any bank assigned to a 
current target with
+ * psoc6_bank_info populated and returns the pointer to the structure
+ * @param target current target
+ * @return pointer to psoc6_bank_info structure or NULL
+ 
*************************************************************************************************/
+static struct psoc6_bank_info *psoc6_get_bank_info_by_target(struct target 
*target)
+{
+       struct flash_bank *bank_iter;
+       struct psoc6_bank_info *info = NULL;
+
+       for (bank_iter = flash_bank_list(); bank_iter; bank_iter = 
bank_iter->next) {
+               if (bank_iter->target != target)
+                       continue;
+
+               if (strcmp(bank_iter->driver->name, "virtual") == 0) {
+                       struct flash_bank *master_bank = 
get_flash_bank_by_name_noprobe(bank_iter->driver_priv);
+                       info = master_bank->driver_priv;
+                       if (info)
+                               break;
+               }
+
+               info = bank_iter->driver_priv;
+               if (info)
+                       break;
+       }
+
+       return info;
+}
 
 /** 
***********************************************************************************************
  * @brief Initializes `struct timeout` structure with given timeout value
  * @param to pointer to `struct timeout` structure
  * @param timeout_ms timeout, in milliseconds
  
*************************************************************************************************/
-static void timeout_init(struct timeout *to, long timeout_ms)
+static void psoc6_timeout_init(struct timeout *to, long timeout_ms)
 {
        to->start_time = timeval_ms();
        to->timeout_ms = timeout_ms;
 }
 
 /** 
***********************************************************************************************
- * @brief Returns true if given `struct timeout` structure has expired
+ * @brief Returns true if given timeout has expired
  * @param to pointer to `struct timeout` structure
  * @return true if timeout expired
  
*************************************************************************************************/
-static bool timeout_expired(struct timeout *to)
+static bool psoc6_timeout_expired(struct timeout *to)
 {
        return (timeval_ms() - to->start_time) > to->timeout_ms;
 }
 
+/** 
***********************************************************************************************
+ * @brief Locates CM0 core of this chip (if present)
+ * @param this_target current target, name should end with 'sysap'
+ * @return pointer to CM0 core (of NULL)
+ 
*************************************************************************************************/
+static struct target *psoc6_find_core_by_suffix(struct target *target, const 
char *suffix)
+{
+       const size_t this_len = strlen(target->cmd_name);
+       size_t last_dot_pos;
+       for (last_dot_pos = this_len; last_dot_pos; last_dot_pos--) {
+               if (target->cmd_name[last_dot_pos] == '.')
+                       break;
+       }
+
+       assert(last_dot_pos != 0);
+
+       last_dot_pos++;
+       char *new_name = calloc(1, last_dot_pos + strlen(suffix) + 1);
+       memcpy(new_name, target->cmd_name, last_dot_pos);
+       new_name = strcat(new_name, suffix);
+
+       struct target *result = NULL;
+       for (result = all_targets; result; result = result->next) {
+               if (target_name(result) && strcmp(new_name, 
target_name(result)) == 0)
+                       break;
+       }
+
+       free(new_name);
+       return result;
+}
+
 /** 
***********************************************************************************************
  * @brief Starts pseudo flash algorithm and leaves it running. Function 
allocates working area for
  * algorithm code and CPU stack, adjusts stack pointer, uploads and starts the 
algorithm.
  * Algorithm (a basic infinite loop) runs asynchronously while driver performs 
Flash operations.
  *
- * @param target target for the algorithm
+ * @param bank current flash bank
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int sromalgo_prepare(struct target *target)
+static int psoc6_sromalgo_prepare(struct flash_bank *bank)
 {
+       struct target *target = bank->target;
+
+       /* Special core_id for fake SysAP */
+       if (target->coreid == 0xFF) {
+               struct target *cm0_target = psoc6_find_core_by_suffix(target, 
"cm0");
+               if (!cm0_target)
+                       return ERROR_OK;
+
+               target = cm0_target;
+       }
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
        int hr;
 
+       struct psoc6_bank_info *info = bank->driver_priv;
+       if (info->prepare_function) {
+               hr = info->prepare_function(bank);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       /* Check if IPC_INTR_MASK contains valid value */
+       uint32_t ipc_intr;
+       hr = target_read_u32(target, info->regs->ipc_intr, &ipc_intr);
+       if (hr != ERROR_OK)
+               return hr;
+
+       /* Enable notification interrupt of IPC_INTR_STRUCT for IPC_STRUCT2 */
+       if (!(ipc_intr & info->regs->ipc_intr_msk)) {
+               hr = target_write_u32(target, info->regs->ipc_intr, ipc_intr | 
info->regs->ipc_intr_msk);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
        /* Initialize Vector Table Offset register (in case FW modified it) */
-       hr = target_write_u32(target, 0xE000ED08, 0x00000000);
+       hr = target_write_u32(target, NVIC_VTOR, 0x00000000);
+       if (hr != ERROR_OK)
+               return hr;
+
+       /* Clear pending interrupts. This resolves the issue that IRQ0/IRQ1 can 
not be
+        * executed when core is HardFault os similar higher-priority handler */
+       const struct armv7m_common *cm = target_to_armv7m(target);
+       hr = mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR, AIRCR_VECTKEY | 
AIRCR_VECTCLRACTIVE);
        if (hr != ERROR_OK)
                return hr;
 
@@ -153,8 +404,8 @@ static int sromalgo_prepare(struct target *target)
        init_reg_param(&reg_params, "sp", 32, PARAM_OUT);
        buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + 
g_stack_area->size);
 
-       /* Write basic infinite loop algorithm to target RAM */
-       hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7);
+       /* Write 'cpsie i' + basic infinite loop algorithm to target RAM */
+       hr = target_write_u32(target, g_stack_area->address, 0xE7FEB662);
        if (hr != ERROR_OK)
                goto destroy_rp_free_wa;
 
@@ -164,16 +415,16 @@ static int sromalgo_prepare(struct target *target)
                goto destroy_rp_free_wa;
 
        destroy_reg_param(&reg_params);
-
        return hr;
 
 destroy_rp_free_wa:
        /* Something went wrong, do some cleanup */
        destroy_reg_param(&reg_params);
 
-       target_free_working_area(target, g_stack_area);
-       g_stack_area = NULL;
-
+       if (g_stack_area) {
+               target_free_working_area(target, g_stack_area);
+               g_stack_area = NULL;
+       }
        return hr;
 }
 
@@ -182,16 +433,23 @@ destroy_rp_free_wa:
  * This function is also used for cleanup in case of errors so g_stack_area 
may be NULL.
  * These cases have to be handled gracefully.
  *
- * @param target current target
+ * @param bank current flash bank
  
*************************************************************************************************/
-static void sromalgo_release(struct target *target)
+static void psoc6_sromalgo_release(struct target *target)
 {
-       int hr = ERROR_OK;
-
        if (g_stack_area) {
+               /* Special core_id for fake SysAP */
+               if (target->coreid == 0xFF) {
+                       struct target *cm0_target = 
psoc6_find_core_by_suffix(target, "cm0");
+                       if (!cm0_target)
+                               return;
+
+                       target = cm0_target;
+               }
+
                /* Stop flash algorithm if it is running */
                if (target->running_alg) {
-                       hr = target_halt(target);
+                       int hr = target_halt(target);
                        if (hr != ERROR_OK)
                                goto exit_free_wa;
 
@@ -215,25 +473,24 @@ exit_free_wa:
  * our data. Locking is performed by ipc_acquire(), this function ensures that 
IPC is actually
  * in expected state
  *
- * @param target current target
- * @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access
+ * @param bank current flash bank
  * @param lock_expected expected lock status
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool 
lock_expected)
+static int ipc_poll_lock_stat(struct flash_bank *bank, bool lock_expected)
 {
-       int hr;
        uint32_t reg_val;
-
        struct timeout to;
-       timeout_init(&to, IPC_TIMEOUT_MS);
+       struct target *target = bank->target;
+       struct psoc6_bank_info *info = bank->driver_priv;
+       psoc6_timeout_init(&to, IPC_TIMEOUT_MS);
 
-       while (!timeout_expired(&to)) {
+       while (!psoc6_timeout_expired(&to)) {
                /* Process any server requests */
                keep_alive();
 
                /* Read IPC Lock status */
-               hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), 
&reg_val);
+               int hr = target_read_u32(target, info->regs->ipc_lock_stat, 
&reg_val);
                if (hr != ERROR_OK) {
                        LOG_ERROR("Unable to read IPC Lock Status register");
                        return hr;
@@ -245,11 +502,6 @@ static int ipc_poll_lock_stat(struct target *target, 
uint32_t ipc_id, bool lock_
                        return ERROR_OK;
        }
 
-       if (target->coreid) {
-               LOG_WARNING("SROM API calls via CM4 target are supported on 
single-core PSoC6 devices only. "
-                       "Please perform all Flash-related operations via CM0+ 
target on dual-core devices.");
-       }
-
        LOG_ERROR("Timeout polling IPC Lock Status");
        return ERROR_TARGET_TIMEOUT;
 }
@@ -260,39 +512,50 @@ static int ipc_poll_lock_stat(struct target *target, 
uint32_t ipc_id, bool lock_
  * This ensures nothing else in the system will use same IPC thus corrupting 
our data.
  * This function locks the IPC.
  *
- * @param target current target
- * @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP 
access
+ * @param bank current flash bank
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int ipc_acquire(struct target *target, char ipc_id)
+static int ipc_acquire(struct flash_bank *bank)
 {
        int hr = ERROR_OK;
        bool is_acquired = false;
-       uint32_t reg_val;
-
+       uint32_t reg_val = 0;
        struct timeout to;
-       timeout_init(&to, IPC_TIMEOUT_MS);
+       struct target *target = bank->target;
+       struct psoc6_bank_info *info = bank->driver_priv;
 
-       while (!timeout_expired(&to)) {
+       psoc6_timeout_init(&to, IPC_TIMEOUT_MS);
+       while (!psoc6_timeout_expired(&to)) {
                keep_alive();
 
-               hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), 
IPC_ACQUIRE_SUCCESS_MSK);
+               /* Workaround for double-buffered PPU */
+               if (info->regs->ppu_flush) {
+                       //enum log_levels level = 
change_debug_level(LOG_LVL_USER);
+                       hr = target_read_u32(target, info->regs->ppu_flush, 
&reg_val);
+                       //change_debug_level(level);
+                       info->ppu_read_protected = (hr != ERROR_OK);
+               }
+
+               /* Acquire the IPC structure */
+               hr = target_write_u32(target, info->regs->ipc_acquire, 
IPC_ACQUIRE_SUCCESS_MSK);
                if (hr != ERROR_OK) {
-                       LOG_ERROR("Unable to write to IPC Acquire register");
+                       LOG_ERROR("Unable to write to IPC Acquire register%s",
+                                         info->ppu_read_protected ? " (PPU 
read-protected)" : "");
                        return hr;
                }
 
                /* Check if data is written on first step */
-               hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), &reg_val);
+               hr = target_read_u32(target, info->regs->ipc_acquire, &reg_val);
                if (hr != ERROR_OK) {
-                       LOG_ERROR("Unable to read IPC Acquire register");
+                       LOG_ERROR("Unable to read IPC Acquire register%s",
+                                         info->ppu_read_protected ? " (PPU 
read-protected)" : "");
                        return hr;
                }
 
                is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
                if (is_acquired) {
                        /* If IPC structure is acquired, the lock status should 
be set */
-                       hr = ipc_poll_lock_stat(target, ipc_id, true);
+                       hr = ipc_poll_lock_stat(bank, true);
                        break;
                }
        }
@@ -304,46 +567,98 @@ static int ipc_acquire(struct target *target, char ipc_id)
 }
 
 /** 
***********************************************************************************************
- * @brief Invokes SROM API functions which are responsible for Flash operations
+ * @brief Helper to detect size of the flash. Reads address space with 
predefined interval and
+ * calculates size of the memory area based on read failures
  *
  * @param target current target
- * @param req_and_params request id of the function to invoke
+ * @param start_addr starting address of the area
+ * @param max_size maximal size of the area
+ * @param step interval size
+ * @return ERROR_OK in case of success, ERROR_XXX code otherwise
+ 
*************************************************************************************************/
+static uint32_t psoc6_probe_mem_area(struct target *target, target_addr_t 
start_addr, uint32_t step,
+       uint32_t max_precision)
+{
+       assert(step && !(step & (step - 1)));
+       assert(start_addr % step == 0);
+       assert(max_precision && !(max_precision & (max_precision - 1)));
+       assert(max_precision >= 4);
+       assert(step > max_precision);
+
+       int hr;
+       uint32_t offset = 0;
+       uint32_t dummy;
+       int steps = 0;
+
+       //enum log_levels old_lvl = change_debug_level(LOG_LVL_USER);
+       while (true) {
+               steps++;
+               hr = target_read_u32(target, start_addr + offset, &dummy);
+               if (hr != ERROR_OK)
+                       break;
+
+               offset += step;
+       }
+
+       while (step > max_precision) {
+               steps++;
+               step = step >> 1;
+               hr = target_read_u32(target, start_addr + offset, &dummy);
+               offset = (hr != ERROR_OK) ? offset - step : offset + step;
+       }
+       //change_debug_level(old_lvl);
+
+       const uint32_t area_size = offset + step;
+       LOG_INFO("Probed Flash Bank @" TARGET_ADDR_FMT ", size %u.%u KiB (in %d 
steps)", start_addr,
+                        area_size >> 10, area_size % 1024, steps);
+
+       return area_size;
+}
+
+/** 
***********************************************************************************************
+ * @brief Invokes SROM API functions which are responsible for Flash operations
+ *
+ * @param bank current flash bank
+ * @param req_and_params requect id of the function to invoke
  * @param working_area address of memory buffer in target's memory space for 
SROM API parameters
+ * @param check_errors true if error check and reporting should be performed
  * @param data_out pointer to variable which will be populated with execution 
status
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int call_sromapi(struct target *target,
-       uint32_t req_and_params,
-       uint32_t working_area,
-       uint32_t *data_out)
+static int psoc6_call_sromapi_inner(struct flash_bank *bank, uint32_t 
req_and_params, uint32_t working_area,
+       bool check_errors, uint32_t *data_out)
 {
-       int hr;
+       LOG_DEBUG("Executing SROM API #0x%08X", req_and_params);
+
+       struct target *target = bank->target;
+
+       if (!g_stack_area && target->coreid != 0xFF) {
+               LOG_ERROR("SROM Call: target is not prepared for srom calls");
+               return ERROR_FAIL;
+       }
 
+       int hr;
+       struct psoc6_bank_info *info = bank->driver_priv;
        bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
 
-       hr = ipc_acquire(target, IPC_ID);
+       hr = ipc_acquire(bank);
        if (hr != ERROR_OK)
                return hr;
 
        if (is_data_in_ram)
-               hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), 
working_area);
+               hr = target_write_u32(target, info->regs->ipc_data, 
working_area);
        else
-               hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), 
req_and_params);
-
-       if (hr != ERROR_OK)
-               return hr;
+               hr = target_write_u32(target, info->regs->ipc_data, 
req_and_params);
 
-       /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for 
IPC_STRUCT2 */
-       hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 
+ IPC_ID));
        if (hr != ERROR_OK)
                return hr;
 
-       hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
+       hr = target_write_u32(target, info->regs->ipc_notify, 1);
        if (hr != ERROR_OK)
                return hr;
 
        /* Poll lock status */
-       hr = ipc_poll_lock_stat(target, IPC_ID, false);
+       hr = ipc_poll_lock_stat(bank, false);
        if (hr != ERROR_OK)
                return hr;
 
@@ -351,57 +666,84 @@ static int call_sromapi(struct target *target,
        if (is_data_in_ram)
                hr = target_read_u32(target, working_area, data_out);
        else
-               hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out);
+               hr = target_read_u32(target, info->regs->ipc_data, data_out);
 
        if (hr != ERROR_OK) {
                LOG_ERROR("Error reading SROM API Status location");
                return hr;
        }
 
-       bool is_success = (*data_out & SROMAPI_STATUS_MSK) == 
SROMAPI_STAT_SUCCESS;
-       if (!is_success) {
-               LOG_ERROR("SROM API execution failed. Status: 0x%08" PRIX32, 
*data_out);
+       bool is_error = (*data_out & SROMAPI_STATUS_MSK) != 
SROMAPI_STAT_SUCCESS;
+       if (check_errors && is_error) {
+               LOG_ERROR("SROM API execution failed. Status: 0x%08X", 
(uint32_t)*data_out);
                return ERROR_TARGET_FAILURE;
        }
 
        return ERROR_OK;
 }
 
+/** 
***********************************************************************************************
+ * @brief Invokes SROM API functions which are responsible for Flash operations
+ *
+ * @param bank current flash bank
+ * @param req_and_params requect id of the function to invoke
+ * @param working_area address of memory buffer in target's memory space for 
SROM API parameters
+ * @param data_out pointer to variable which will be populated with execution 
status
+ * @return ERROR_OK in case of success, ERROR_XXX code otherwise
+ 
*************************************************************************************************/
+static int psoc6_call_sromapi(struct flash_bank *bank, uint32_t 
req_and_params, uint32_t working_area,
+       uint32_t *data_out)
+{
+       return psoc6_call_sromapi_inner(bank, req_and_params, working_area, 
true, data_out);
+}
+
 /** 
***********************************************************************************************
  * @brief Retrieves SiliconID and Protection status of the target device
- * @param target current target
- * @param si_id pointer to variable, will be populated with SiliconID
+ * @param bank current flash bank
+ * @param si_id pointer to variable, will be populated with SiliconID of the 
following format:
+ *  [31:24]       | [23:16]       | [15:12]       | [11:8]             | [7:0]
+ *  Silicon Id Hi | Silicon ID Lo | Major Rev. Id | Minor Rev. Id | Family Id 
Lo
  * @param protection pointer to variable, will be populated with protection 
status
+ * @param lifecycle pointer to variable, will be populated with lifecycle state
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t 
*protection)
+static int psoc6_get_silicon_id(struct flash_bank *bank, uint32_t *si_id, 
uint8_t *protection, uint8_t *lifecycle)
 {
        int hr;
        uint32_t family_rev, siid_prot;
+       struct target *target = bank->target;
 
-       hr = sromalgo_prepare(target);
+       hr = psoc6_sromalgo_prepare(bank);
        if (hr != ERROR_OK)
                goto exit;
 
-       /* Read FamilyID and Revision */
-       hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, 
&family_rev);
+       /* SiliconID SROM API returns:
+                          | [31:28]               | [23:20]               | 
[19:16]               | [15:8]        | [7:0]               |
+          
----------------------------------------------------------------------------------------------------
+          Type 0: | Status Code = 0xA | Major Revision Id | Minor Revision Id 
| Family Id Hi | Family Id Lo  |
+          Type 1: | Status Code = 0xA | Not used                 | Protection 
state  | Silicon Id Hi| Silicon ID Lo |
+          Type 2: | Status Code = 0xA | Not used                 | Not used    
          | SROM FW major| SROM FW minor | */
+
+       /* Type 0: Get Family ID and Revision ID */
+       hr = psoc6_call_sromapi(bank, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, 
&family_rev);
        if (hr != ERROR_OK)
                goto exit;
 
-       /* Read SiliconID and Protection */
-       hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, 
&siid_prot);
+       /* Type 1: Get Silicon ID, Protection state and Life Cycle stage */
+       hr = psoc6_call_sromapi(bank, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, 
&siid_prot);
        if (hr != ERROR_OK)
                goto exit;
 
-       *si_id  = (siid_prot & 0x0000FFFF) << 16;
-       *si_id |= (family_rev & 0x00FF0000) >> 8;
-       *si_id |= (family_rev & 0x000000FF) >> 0;
+       *si_id  = (siid_prot & 0x0000FFFF) << 16; /* si_id[31:24] = Silicon Id 
Hi, si_id[23:16] = Silicon ID Lo */
+       *si_id |= (family_rev & 0x00FF0000) >> 8; /* si_id[15:12] = Major Rev. 
Id, si_id[11:8]  = Minor Rev. Id */
+       *si_id |= (family_rev & 0x000000FF) >> 0; /* si_id[7:0]   = Family Id 
Lo */
 
        *protection = (siid_prot & 0x000F0000) >> 0x10;
+       *lifecycle = (siid_prot & 0x00F00000) >> 0x14;
 
 exit:
-       sromalgo_release(target);
-       return ERROR_OK;
+       psoc6_sromalgo_release(target);
+       return hr;
 }
 
 /** 
***********************************************************************************************
@@ -412,21 +754,23 @@ exit:
 static int psoc6_protect_check(struct flash_bank *bank)
 {
        int is_protected;
+       uint32_t silicon_id;
+       uint8_t protection;
+       uint8_t lifecycle;
 
-       struct psoc6_target_info *psoc6_info = bank->driver_priv;
-       int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, 
&psoc6_info->protection);
+       int hr = psoc6_get_silicon_id(bank, &silicon_id, &protection, 
&lifecycle);
        if (hr != ERROR_OK)
                return hr;
 
-       switch (psoc6_info->protection) {
-               case PROTECTION_VIRGIN:
-               case PROTECTION_NORMAL:
+       switch (protection) {
+               case CHIP_PROT_VIRGIN:
+               case CHIP_PROT_NORMAL:
                        is_protected = 0;
                        break;
 
-               case PROTECTION_UNKNOWN:
-               case PROTECTION_SECURE:
-               case PROTECTION_DEAD:
+               case CHIP_PROT_UNKNOWN:
+               case CHIP_PROT_SECURE:
+               case CHIP_PROT_DEAD:
                default:
                        is_protected = 1;
                        break;
@@ -438,106 +782,93 @@ static int psoc6_protect_check(struct flash_bank *bank)
        return ERROR_OK;
 }
 
-/** 
***********************************************************************************************
- * @brief Dummy function, Life Cycle transition is not currently supported
- * @return ERROR_OK always
- 
*************************************************************************************************/
-static int psoc6_protect(struct flash_bank *bank, int set, unsigned int first,
-               unsigned int last)
-{
-       (void)bank;
-       (void)set;
-       (void)first;
-       (void)last;
-
-       LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
-       return ERROR_OK;
-}
-
 /** 
***********************************************************************************************
  * @brief Translates Protection status to string
  * @param protection protection value
- * @return pointer to const string describing protection status
+ * @return pointer to const string describintg protection status
  
*************************************************************************************************/
 static const char *protection_to_str(uint8_t protection)
 {
-       switch (protection) {
-               case PROTECTION_VIRGIN:
-                       return "VIRGIN";
-               case PROTECTION_NORMAL:
-                       return "NORMAL";
-               case PROTECTION_SECURE:
-                       return "SECURE";
-               case PROTECTION_DEAD:
-                       return "DEAD";
-               case PROTECTION_UNKNOWN:
-               default:
-                       return "UNKNOWN";
-       }
+       static const char *const prot_states[] = {"UNKNOWN", "VIRGIN", 
"NORMAL", "SECURE", "DEAD"};
+       if (protection > 4)
+               protection = 0;
+       return prot_states[protection];
 }
 
 /** 
***********************************************************************************************
  * @brief psoc6_get_info Displays human-readable information about acquired 
device
  * @param bank current flash bank
- * @param cmd pointer to command invocation instance
+ * @param buf pointer to buffer for human-readable text
+ * @param buf_size size of the buffer
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
 static int psoc6_get_info(struct flash_bank *bank, struct command_invocation 
*cmd)
 {
-       struct psoc6_target_info *psoc6_info = bank->driver_priv;
+       struct psoc6_bank_info *info = bank->driver_priv;
 
-       if (psoc6_info->is_probed == false)
+       if (!info->is_probed)
                return ERROR_FAIL;
 
-       int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, 
&psoc6_info->protection);
+       uint32_t silicon_id;
+       uint8_t protection;
+       uint8_t lifecycle;
+
+       int hr = psoc6_get_silicon_id(bank, &silicon_id, &protection, 
&lifecycle);
        if (hr != ERROR_OK)
                return hr;
 
-       command_print_sameline(cmd,
-               "PSoC6 Silicon ID: 0x%08" PRIX32 "\n"
-               "Protection: %s\n"
-               "Main Flash size: %" PRIu32 " kB\n"
-               "Work Flash size: 32 kB\n",
-               psoc6_info->silicon_id,
-               protection_to_str(psoc6_info->protection),
-               psoc6_info->main_flash_sz / 1024);
+       command_print_sameline(cmd, "Silicon ID: 0x%08X\nProtection: %s",
+               silicon_id, protection_to_str(protection));
 
        return ERROR_OK;
 }
 
 /** 
***********************************************************************************************
- * @brief Checks if given flash bank belongs to Supervisory Flash
- * @param bank current flash bank
- * @return true if flash bank belongs to Supervisory Flash
+ * @brief Checks if given flash row belongs to Safe Supervisory Flash region
+ * @param addr row start address to check
+ * @param op type of operation to check safety for
+ * @return true if flash bank belongs to Safe Supervisory Flash region
  
*************************************************************************************************/
-static bool is_sflash_bank(struct flash_bank *bank)
+static bool psoc6_is_safe_sflash_page(struct psoc6_bank_info *info, uint32_t 
addr, enum operation op)
 {
-       for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
-               if (bank->base == safe_sflash_regions[i].addr)
-                       return true;
+       assert(addr % 512 == 0);
+
+       /* At restriction level 3 all writes are allowed except during erase */
+       if (op == PROGRAM && g_sflash_restrictions == 3)
+               return true;
+
+       for (size_t i = 0; i < 4; i++) {
+               target_addr_t region_start = info->sflash_regions[i].addr;
+               uint32_t region_size = info->sflash_regions[i].size;
+
+               if (addr >= region_start && addr < region_start + region_size) {
+                       if (op == ERASE) {
+                               return (info->sflash_regions[i].flags & (1u << 
(g_sflash_restrictions + 0)));
+                       } else { /* op == PROGRAM */
+                               return (info->sflash_regions[i].flags & (1u << 
(g_sflash_restrictions + 4)));
+                       }
+               }
        }
 
        return false;
 }
 
 /** 
***********************************************************************************************
- * @brief Checks if given flash bank belongs to Work Flash
+ * @brief Checks if given flash bank base address is one in the addr_array 
array
  * @param bank current flash bank
- * @return true if flash bank belongs to Work Flash
+ * @param addr_array array with base addresses
+ * @return true if flash bank matches
  
*************************************************************************************************/
-static inline bool is_wflash_bank(struct flash_bank *bank)
+static bool psoc6_flash_bank_matches(struct flash_bank *bank, const struct 
bank_match *match)
 {
-       return (bank->base == MEM_BASE_WFLASH);
-}
+       uint32_t idx = 0;
+       while (match[idx].address_mask) {
+               if ((bank->base & match[idx].address_mask) == 
match[idx].address_value)
+                       return true;
+               idx++;
+       }
 
-/** 
***********************************************************************************************
- * @brief Checks if given flash bank belongs to Main Flash
- * @param bank current flash bank
- * @return true if flash bank belongs to Main Flash
- 
*************************************************************************************************/
-static inline bool is_mflash_bank(struct flash_bank *bank)
-{
-       return (bank->base == MEM_BASE_MFLASH);
+       return false;
 }
 
 /** 
***********************************************************************************************
@@ -550,38 +881,31 @@ static inline bool is_mflash_bank(struct flash_bank *bank)
  
*************************************************************************************************/
 static int psoc6_probe(struct flash_bank *bank)
 {
+       struct psoc6_bank_info *info = bank->driver_priv;
        struct target *target = bank->target;
-       struct psoc6_target_info *psoc6_info = bank->driver_priv;
-
-       int hr = ERROR_OK;
 
-       /* Retrieve data from SPCIF_GEOMETRY */
-       uint32_t geom;
-       target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom);
-       uint32_t row_sz_lg2 = (geom & 0xF0) >> 4;
-       uint32_t row_sz = (0x01 << row_sz_lg2);
-       uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8);
-       uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24);
-
-       /* Calculate size of Main Flash*/
-       uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz;
-
-       free(bank->sectors);
-       bank->sectors = NULL;
+       if (bank->sectors) {
+               free(bank->sectors);
+               bank->sectors = NULL;
+               bank->num_sectors = 0;
+       }
 
+       uint32_t row_sz = 512;
        size_t bank_size = 0;
 
-       if (is_mflash_bank(bank))
-               bank_size = flash_sz_bytes;
-       else if (is_wflash_bank(bank))
-               bank_size = MEM_WFLASH_SIZE;
-       else if (is_sflash_bank(bank)) {
-               for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
-                       if (safe_sflash_regions[i].addr == bank->base) {
-                               bank_size = safe_sflash_regions[i].size;
-                               break;
-                       }
+       if (psoc6_flash_bank_matches(bank, info->regs->mem_base_main)) {
+               if (!info->size_override)
+                       info->size_override = psoc6_probe_mem_area(target, 
bank->base, k_b(128), k_b(1));
+
+               if (!info->size_override) {
+                       LOG_ERROR("MainFlash size is unknown");
+                       return ERROR_FLASH_BANK_INVALID;
                }
+               bank_size = info->size_override;
+       } else if (psoc6_flash_bank_matches(bank, info->regs->mem_base_work)) {
+               bank_size = MEM_WFLASH_SIZE;
+       } else if (psoc6_flash_bank_matches(bank, info->regs->mem_base_sflash)) 
{
+               bank_size = MEM_SFLASH_SIZE;
        }
 
        if (bank_size == 0) {
@@ -589,26 +913,24 @@ static int psoc6_probe(struct flash_bank *bank)
                return ERROR_FLASH_BANK_INVALID;
        }
 
-       unsigned int num_sectors = bank_size / row_sz;
+       size_t num_sectors = bank_size / row_sz;
        bank->size = bank_size;
+       bank->num_sectors = num_sectors;
 
+       bank->chip_width = 4;
+       bank->bus_width = 4;
        bank->erased_value = 0;
        bank->default_padded_value = 0;
+       bank->sectors = alloc_block_array(0, row_sz, num_sectors);
 
-       bank->num_sectors = num_sectors;
-       bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
-       for (unsigned int i = 0; i < num_sectors; i++) {
-               bank->sectors[i].size = row_sz;
-               bank->sectors[i].offset = i * row_sz;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = -1;
-       }
+       bank->write_start_alignment = row_sz;
+       bank->write_end_alignment = row_sz;
+       bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
 
-       psoc6_info->is_probed = true;
-       psoc6_info->main_flash_sz = flash_sz_bytes;
-       psoc6_info->row_sz = row_sz;
+       info->page_size = row_sz;
+       info->is_probed = true;
 
-       return hr;
+       return ERROR_OK;
 }
 
 /** 
***********************************************************************************************
@@ -618,133 +940,309 @@ static int psoc6_probe(struct flash_bank *bank)
  
*************************************************************************************************/
 static int psoc6_auto_probe(struct flash_bank *bank)
 {
-       struct psoc6_target_info *psoc6_info = bank->driver_priv;
-       int hr;
-
-       if (psoc6_info->is_probed)
-               hr = ERROR_OK;
-       else
-               hr = psoc6_probe(bank);
-
-       return hr;
+       struct psoc6_bank_info *info = bank->driver_priv;
+       return info->is_probed ? ERROR_OK : psoc6_probe(bank);
 }
 
 /** 
***********************************************************************************************
- * @brief Erases single sector (256k) on target device
+ * @brief Erases single Row or Sector on target device
  * @param bank current flash bank
- * @param wa working area for SROM API parameters
- * @param addr starting address of the sector
+ * @param addr starting address of the flash row
+ * @param erase_sector if true will erase sector, erases row otherwise
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int psoc6_erase_sector(struct flash_bank *bank, struct working_area 
*wa, uint32_t addr)
+static int psoc6_erase_row(struct flash_bank *bank, uint32_t addr, bool 
erase_sector)
 {
+       const bool is_flash_ctrl1 = (bank->base & FLASH_CONTROLLER_1_MSK);
+       const uint32_t erase_sector_req = is_flash_ctrl1 ? 
SROMAPI_ERASESECTOR1_REQ : SROMAPI_ERASESECTOR0_REQ;
        struct target *target = bank->target;
+       struct working_area *wa;
 
-       LOG_DEBUG("Erasing SECTOR @%08" PRIX32, addr);
+       LOG_DEBUG("PSoC6 platform: erasing row @%08X", addr);
+       uint8_t srom_params[2 * sizeof(uint32_t)];
 
-       int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ);
+       int hr = target_alloc_working_area(target, sizeof(srom_params), &wa);
        if (hr != ERROR_OK)
-               return hr;
+               goto exit;
 
-       hr = target_write_u32(target, wa->address + 0x04, addr);
+       buf_set_u32(srom_params + 0x00, 0, 32, erase_sector ? erase_sector_req 
: SROMAPI_ERASEROW_REQ);
+       buf_set_u32(srom_params + 0x04, 0, 32, addr);
+
+       hr = target_write_buffer(target, wa->address, sizeof(srom_params), 
srom_params);
        if (hr != ERROR_OK)
-               return hr;
+               goto exit_free_wa;
 
        uint32_t data_out;
-       hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, 
&data_out);
-       if (hr != ERROR_OK)
-               LOG_ERROR("SECTOR @%08" PRIX32 " not erased!", addr);
+       hr = psoc6_call_sromapi(bank, SROMAPI_ERASEROW_REQ, wa->address, 
&data_out);
+
+exit_free_wa:
+       target_free_working_area(target, wa);
 
+exit:
        return hr;
 }
 
+static int psoc6_program(struct flash_bank *bank, const uint8_t *buffer, 
uint32_t offset,
+       uint32_t count);
+static int psoc6_program_row(struct flash_bank *bank, uint32_t addr, const 
uint8_t *buffer, bool use_writerow);
+static int psoc6_erase_with_algo(struct flash_bank *bank, int first, int last, 
erase_builder erase_builder_p);
+static int psoc6_program_with_algo(struct flash_bank *bank, const uint8_t 
*buffer, uint32_t offset, uint32_t count);
+
+
 /** 
***********************************************************************************************
- * @brief Erases single row (512b) on target device
- * @param bank current flash bank
- * @param wa working area for SROM API parameters
- * @param addr starting address of the flash row
- * @return ERROR_OK in case of success, ERROR_XXX code otherwise
+ * @brief Erases Supervisory Flash by programming it with zeros
+ * @param bank the current flash bank
+ * @param first the first sector to erase
+ * @param last the last sector to erase
+ * @return ERROR_OK, all errors are ignored (but reported)
  
*************************************************************************************************/
-static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, 
uint32_t addr)
+static int psoc6_erase_sflash(struct flash_bank *bank, int first, int last)
 {
+       uint32_t offset = bank->sectors[first].offset;
+       uint32_t count = bank->sectors[last].offset + bank->sectors[last].size 
- offset;
+       uint8_t *buffer = calloc(1, count);
+       uint8_t *const_buffer = buffer;
+       bool erase_skipped = false;
        struct target *target = bank->target;
+       struct psoc6_bank_info *info = bank->driver_priv;
+       int hr;
 
-       LOG_DEBUG("Erasing ROW @%08" PRIX32, addr);
+       const bool is_sflash = psoc6_flash_bank_matches(bank, 
info->regs->mem_base_sflash);
+       assert(is_sflash);
 
-       int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ);
+       memset(buffer, bank->erased_value, count);
+       hr = psoc6_sromalgo_prepare(bank);
        if (hr != ERROR_OK)
-               return hr;
+               goto exit;
 
-       hr = target_write_u32(target, wa->address + 0x04, addr);
-       if (hr != ERROR_OK)
-               return hr;
+       //progress_init(count / info->page_size, ERASING);
+       for (size_t i = 0; i < count / info->page_size; i++) {
+               const uint32_t row_addr = bank->base + offset + i * 
info->page_size;
+               if (psoc6_is_safe_sflash_page(info, row_addr, ERASE)) {
+                       hr = psoc6_program_row(bank, row_addr, buffer, 
is_sflash);
+                       if (hr != ERROR_OK)
+                               LOG_ERROR("Failed to program Flash at address 
0x%08X", row_addr);
+               } else {
+                       erase_skipped = true;
+               }
 
-       uint32_t data_out;
-       hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out);
-       if (hr != ERROR_OK)
-               LOG_ERROR("ROW @%08" PRIX32 " not erased!", addr);
+               //progress_sofar(i + 1);
+               buffer += info->page_size;
+       }
+       hr = ERROR_OK;
+
+exit:
+       free(const_buffer);
+       psoc6_sromalgo_release(target);
+       //progress_done(hr);
+
+       if (erase_skipped)
+               LOG_WARNING("Some SFlash rows were skipped during erase, see 
'sflash_restrictions' command");
 
        return hr;
 }
 
 /** 
***********************************************************************************************
- * @brief Performs Erase operation. Function will try to use biggest erase 
block possible to
- * speedup the operation.
- *
+ * @brief builds data buffer with list of sectors addresses to erase
  * @param bank current flash bank
  * @param first first sector to erase
  * @param last last sector to erase
- * @return ERROR_OK in case of success, ERROR_XXX code otherwise
+ * @param address_buffer pointer to the buffer
+ * @return number of addresses in the buffer
  
*************************************************************************************************/
-static int psoc6_erase(struct flash_bank *bank, unsigned int first,
-               unsigned int last)
+static size_t psoc6_erase_builder(struct flash_bank *bank, int first, int 
last, uint32_t *address_buffer)
 {
-       struct target *target = bank->target;
-       struct psoc6_target_info *psoc6_info = bank->driver_priv;
-       const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE 
: MFLASH_SECTOR_SIZE;
+       struct psoc6_bank_info *info = bank->driver_priv;
+       uint32_t sector_size = 0;
 
-       int hr;
-       struct working_area *wa;
+       if (psoc6_flash_bank_matches(bank, info->regs->mem_base_work))
+               sector_size = WFLASH_SECTOR_SIZE;
+       else if (psoc6_flash_bank_matches(bank, info->regs->mem_base_main))
+               sector_size = bank->size > k_b(256) ? MFLASH_SECTOR_SIZE_256K : 
MFLASH_SECTOR_SIZE_128K;
 
-       if (is_sflash_bank(bank)) {
-               LOG_INFO("Erase operation on Supervisory Flash is not required, 
skipping");
-               return ERROR_OK;
-       }
+       assert(sector_size != 0);
 
-       hr = sromalgo_prepare(target);
-       if (hr != ERROR_OK)
-               goto exit;
+       /* Number of rows in single sector */
+       const int rows_in_sector = sector_size / info->page_size;
+       const int rows_in_sub_sector = 8;
+       size_t sector_count = 0;
 
-       hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
+       while (last >= first) {
+               const uint32_t address = bank->base + first * info->page_size;
+               if ((first % rows_in_sector) == 0 && (last - first + 1) >= 
rows_in_sector) {
+                       /* Erase Sector if we are on sector boundary and erase 
size covers whole sector */
+                       address_buffer[sector_count++] = address | 1u;
+                       first += rows_in_sector;
+               } else if (!info->has_erase_subsector_bug &&
+                                 (first % rows_in_sub_sector) == 0 && (last - 
first + 1) >= rows_in_sub_sector) {
+                       /* Erase Sub-Sector if we are on sub-sector boundary 
and erase size covers whole sub-sector */
+                       address_buffer[sector_count++] = address | 2u;
+                       first += rows_in_sub_sector;
+               } else {
+                       /* Erase Row otherwise */
+                       address_buffer[sector_count++] = address;
+                       first += 1;
+               }
+       }
+
+       return sector_count;
+}
+
+/** 
***********************************************************************************************
+ * @brief Performs Erase operation. Function will try to use biggest erase 
block possible to
+ * speedup the operation.
+ * @param bank the current flash bank
+ * @param first the first sector to erase
+ * @param last the last sector to erase
+ * @return ERROR_OK in case of success, ERROR_XXX code otherwise
+ 
*************************************************************************************************/
+static int psoc6_erase(struct flash_bank *bank, unsigned int first, unsigned 
int last)
+{
+       struct psoc6_bank_info *info = bank->driver_priv;
+
+       if (psoc6_flash_bank_matches(bank, info->regs->mem_base_sflash))
+               return psoc6_erase_sflash(bank, first, last);
+
+       if (bank->target->coreid != 0xFF)
+               return psoc6_erase_with_algo(bank, first, last, 
psoc6_erase_builder);
+
+       /* Fallback for SYS_AP */
+       struct target *target = bank->target;
+       int hr = psoc6_sromalgo_prepare(bank);
        if (hr != ERROR_OK)
                goto exit;
 
+       uint32_t sector_size = 0;
+       if (psoc6_flash_bank_matches(bank, info->regs->mem_base_work))
+               sector_size = WFLASH_SECTOR_SIZE;
+       else if (psoc6_flash_bank_matches(bank, info->regs->mem_base_main))
+               sector_size = bank->size > k_b(256) ? MFLASH_SECTOR_SIZE_256K : 
MFLASH_SECTOR_SIZE_128K;
+
+       assert(sector_size != 0);
+
        /* Number of rows in single sector */
-       const unsigned int rows_in_sector = sector_size / psoc6_info->row_sz;
+       const unsigned int rows_in_sector = sector_size / info->page_size;
 
+       //progress_init(last - first + 1, ERASING);
        while (last >= first) {
+               const uint32_t address = bank->base + first * info->page_size;
                /* Erase Sector if we are on sector boundary and erase size 
covers whole sector */
-               if ((first % rows_in_sector) == 0 &&
-                       (last - first + 1) >= rows_in_sector) {
-                       hr = psoc6_erase_sector(bank, wa, bank->base + first * 
psoc6_info->row_sz);
+               if ((first % rows_in_sector) == 0 && (last - first + 1) >= 
rows_in_sector) {
+                       hr = psoc6_erase_row(bank, address, true);
                        if (hr != ERROR_OK)
-                               goto exit_free_wa;
+                               goto exit;
 
                        first += rows_in_sector;
                } else {
                        /* Perform Row Erase otherwise */
-                       hr = psoc6_erase_row(bank, wa, bank->base + first * 
psoc6_info->row_sz);
+                       hr = psoc6_erase_row(bank, address, false);
                        if (hr != ERROR_OK)
-                               goto exit_free_wa;
+                               goto exit;
 
                        first += 1;
                }
+               //progress_left(last - first + 1);
        }
 
-exit_free_wa:
-       target_free_working_area(target, wa);
 exit:
-       sromalgo_release(target);
+       psoc6_sromalgo_release(target);
+       //progress_done(hr);
+       return hr;
+}
+
+/** 
***********************************************************************************************
+ * @brief Performs Erase operation using asynchronous flash algorithm
+ * @param bank the current flash bank
+ * @param first the first sector to erase
+ * @param last the last sector to erase
+ * @param erase_builder_p pointer to erase_builder function
+ * @return ERROR_OK in case of success, ERROR_XXX code otherwise
+ 
*************************************************************************************************/
+static int psoc6_erase_with_algo(struct flash_bank *bank, int first, int last, 
erase_builder erase_builder_p)
+{
+       int hr;
+       struct target *target = bank->target;
+       struct psoc6_bank_info *info = bank->driver_priv;
+
+       const size_t algo_size = info->erase_algo_size;
+       const uint8_t *algo_p = info->erase_algo_p;
+
+       struct working_area *wa_algorithm;
+       struct working_area *wa_stack;
+       struct working_area *wa_buffer;
+
+       uint32_t address_buffer[last - first + 1];
+       memset(address_buffer, 0, sizeof(address_buffer));
+
+       if (info->prepare_function) {
+               hr = info->prepare_function(bank);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       /* Allocate buffer for the algorithm */
+       hr = target_alloc_working_area(target, algo_size, &wa_algorithm);
+       if (hr != ERROR_OK)
+               return hr;
+
+       /* Write the algorithm code */
+       hr = target_write_buffer(target, wa_algorithm->address, algo_size, 
algo_p);
+       if (hr != ERROR_OK)
+               goto err_free_wa_algo;
+
+       /* Allocate buffer for the stack */
+       hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &wa_stack);
+       if (hr != ERROR_OK)
+               goto err_free_wa_algo;
+
+       /* Allocate circular buffer for 16 addresses, this should be sufficient 
*/
+       hr = target_alloc_working_area(target, 16 * sizeof(uint32_t) + 8, 
&wa_buffer);
+       if (hr != ERROR_OK)
+               goto err_free_wa_stack;
+
+       size_t num_addresses_in_buffer = erase_builder_p(bank, first, last, 
address_buffer);
+       struct armv7m_algorithm armv7m_algo;
+       armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_algo.core_mode = ARM_MODE_THREAD;
+
+       struct reg_param reg_params[4];
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "sp", 32, PARAM_OUT);
+
+       buf_set_u32(reg_params[0].value, 0, 32, wa_buffer->address);
+       buf_set_u32(reg_params[1].value, 0, 32, wa_buffer->address + 
wa_buffer->size);
+       buf_set_u32(reg_params[2].value, 0, 32, num_addresses_in_buffer);
+       buf_set_u32(reg_params[3].value, 0, 32, wa_stack->address + 
wa_stack->size);
+
+       //progress_init(0, ERASING);
+       hr = target_run_flash_async_algorithm(target, (const uint8_t 
*)address_buffer, num_addresses_in_buffer,
+                       sizeof(uint32_t), 0, NULL, ARRAY_SIZE(reg_params), 
reg_params,
+                       wa_buffer->address, wa_buffer->size,
+                       wa_algorithm->address, 0, &armv7m_algo);
+
+       if (hr != ERROR_OK) {
+               uint32_t srom_result = buf_get_u32(reg_params[0].value, 0, 32);
+               if ((srom_result & SROMAPI_STATUS_MSK) != SROMAPI_STAT_SUCCESS) 
{
+                       LOG_ERROR("SROM API execution failed. Status: 0x%08X", 
srom_result);
+                       hr = ERROR_FAIL;
+               }
+       }
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+
+       target_free_working_area(target, wa_buffer);
+
+err_free_wa_stack:
+       target_free_working_area(target, wa_stack);
+
+err_free_wa_algo:
+       target_free_working_area(target, wa_algorithm);
+
        return hr;
 }
 
@@ -753,50 +1251,46 @@ exit:
  * @param bank current flash bank
  * @param addr address of the flash row
  * @param buffer pointer to the buffer with data
- * @param is_sflash true if current flash bank belongs to Supervisory Flash
+ * @param use_writerow true if current flash bank belongs to Supervisory Flash
+ * @param data_size - size of data to be programmed
+ *   0 – 1 byte         1 - 2 bytes    2 - 4 bytes      3 – 8 bytes     4 – 16 
bytes
+ *   5 – 32 bytes   6 – 64 bytes   7 - 128 bytes   8 - 256 bytes   9 - 512 
bytes
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int psoc6_program_row(struct flash_bank *bank,
-       uint32_t addr,
-       const uint8_t *buffer,
-       bool is_sflash)
+static int psoc6_program_row_inner(struct flash_bank *bank, uint32_t addr, 
const uint8_t *buffer,
+       bool use_writerow, uint8_t data_size)
 {
+       const bool is_flash_ctrl1 = (bank->base & FLASH_CONTROLLER_1_MSK);
+       const uint32_t program_row_req = is_flash_ctrl1 ? 
SROMAPI_PROGRAMROW1_REQ : SROMAPI_PROGRAMROW0_REQ;
+
        struct target *target = bank->target;
-       struct psoc6_target_info *psoc6_info = bank->driver_priv;
        struct working_area *wa;
-       const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : 
SROMAPI_PROGRAMROW_REQ;
+       const uint32_t sromapi_req = use_writerow ? SROMAPI_WRITEROW_REQ : 
program_row_req;
+       const size_t num_bytes = (1u << data_size);
        uint32_t data_out;
-       int hr = ERROR_OK;
+       int hr;
 
-       LOG_DEBUG("Programming ROW @%08" PRIX32, addr);
+       LOG_DEBUG("PSoC6 platform: programming row @%08X", addr);
+       uint8_t srom_params[4 * sizeof(uint32_t)];
 
-       hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
+       hr = target_alloc_working_area(target, sizeof(srom_params) + num_bytes, 
&wa);
        if (hr != ERROR_OK)
                goto exit;
 
-       hr = target_write_u32(target, wa->address, sromapi_req);
-       if (hr != ERROR_OK)
-               goto exit_free_wa;
-
-       hr = target_write_u32(target,
-                       wa->address + 0x04,
-                       0x106);
-       if (hr != ERROR_OK)
-               goto exit_free_wa;
-
-       hr = target_write_u32(target, wa->address + 0x08, addr);
-       if (hr != ERROR_OK)
-               goto exit_free_wa;
+       buf_set_u32(srom_params + 0x00, 0, 32, sromapi_req);
+       buf_set_u32(srom_params + 0x04, 0, 32, 0x100 | data_size);
+       buf_set_u32(srom_params + 0x08, 0, 32, addr);
+       buf_set_u32(srom_params + 0x0C, 0, 32, wa->address + 0x10);
 
-       hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
+       hr = target_write_buffer(target, wa->address, sizeof(srom_params), 
srom_params);
        if (hr != ERROR_OK)
                goto exit_free_wa;
 
-       hr = target_write_buffer(target, wa->address + 0x10, 
psoc6_info->row_sz, buffer);
+       hr = target_write_buffer(target, wa->address + 0x10, num_bytes, buffer);
        if (hr != ERROR_OK)
                goto exit_free_wa;
 
-       hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
+       hr = psoc6_call_sromapi(bank, sromapi_req, wa->address, &data_out);
 
 exit_free_wa:
        target_free_working_area(target, wa);
@@ -805,73 +1299,201 @@ exit:
        return hr;
 }
 
+/** 
***********************************************************************************************
+ * @brief Programs single Flash Row
+ * @param bank current flash bank
+ * @param addr address of the flash row
+ * @param buffer pointer to the buffer with data
+ * @param use_writerow true if current flash bank belongs to Supervisory Flash
+ * @return ERROR_OK in case of success, ERROR_XXX code otherwise
+ 
*************************************************************************************************/
+static int psoc6_program_row(struct flash_bank *bank, uint32_t addr, const 
uint8_t *buffer, bool use_writerow)
+{
+       return psoc6_program_row_inner(bank, addr, buffer, use_writerow, 9);
+}
+
+
 /** 
***********************************************************************************************
  * @brief Performs Program operation
  * @param bank current flash bank
  * @param buffer pointer to the buffer with data
- * @param offset starting offset in flash bank
+ * @param offset starting offset in falsh bank
  * @param count number of bytes in buffer
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int psoc6_program(struct flash_bank *bank,
-       const uint8_t *buffer,
-       uint32_t offset,
-       uint32_t count)
+static int psoc6_program(struct flash_bank *bank, const uint8_t *buffer, 
uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
-       struct psoc6_target_info *psoc6_info = bank->driver_priv;
-       const bool is_sflash = is_sflash_bank(bank);
-       int hr;
+       struct psoc6_bank_info *info = bank->driver_priv;
+       int hr = ERROR_OK;
+       bool program_skipped = false;
+
+       assert(offset % info->page_size == 0);
+       assert(count % info->page_size == 0);
+
+       const bool is_sflash = psoc6_flash_bank_matches(bank, 
info->regs->mem_base_sflash);
 
-       uint8_t page_buf[psoc6_info->row_sz];
+       if (!is_sflash && target->coreid != 0xFF) { /* Special core_id for fake 
SysAP */
+               hr = psoc6_program_with_algo(bank, buffer, offset, count);
+               if (hr == ERROR_OK || hr != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       return hr;
+       }
 
-       hr = sromalgo_prepare(target);
+       hr = psoc6_sromalgo_prepare(bank);
        if (hr != ERROR_OK)
                goto exit;
 
-       while (count) {
-               uint32_t row_offset = offset % psoc6_info->row_sz;
-               uint32_t aligned_addr = bank->base + offset - row_offset;
-               uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, 
count);
+       //progress_init(count / info->page_size, PROGRAMMING);
+       for (size_t i = 0; i < count / info->page_size; i++) {
+               const uint32_t page_addr = bank->base + offset + i * 
info->page_size;
+               const bool is_safe_sflash_page = 
psoc6_is_safe_sflash_page(info, page_addr, PROGRAM);
 
-               memset(page_buf, 0, sizeof(page_buf));
-               memcpy(&page_buf[row_offset], buffer, row_bytes);
+               if (!is_sflash || is_safe_sflash_page) {
+                       hr = psoc6_program_row(bank, page_addr, buffer, 
is_sflash);
+                       if (hr != ERROR_OK) {
+                               LOG_ERROR("Failed to program Flash at address 
0x%08X", page_addr);
 
-               hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash);
-               if (hr != ERROR_OK) {
-                       LOG_ERROR("Failed to program Flash at address 0x%08" 
PRIX32, aligned_addr);
-                       goto exit;
+                               /* Ignore possigle errors in case we are 
dealing with SFlash */
+                               if (!is_sflash)
+                                       goto exit;
+                       }
+               } else {
+                       if (is_sflash)
+                               program_skipped = true;
                }
-
-               buffer += row_bytes;
-               offset += row_bytes;
-               count -= row_bytes;
+               //progress_sofar(i + 1);
+               buffer += info->page_size;
        }
 
 exit:
-       sromalgo_release(target);
+       psoc6_sromalgo_release(target);
+       //progress_done(hr);
+
+       if (program_skipped)
+               LOG_WARNING("Some SFlash rows were skipped during programming, 
see 'sflash_restrictions' command");
+
        return hr;
 }
 
 /** 
***********************************************************************************************
- * @brief Performs Mass Erase operation
+ * @brief Performs Program operation
+ * @param bank current flash bank
+ * @param buffer pointer to the buffer with data
+ * @param offset starting offset in falsh bank
+ * @param count number of bytes in buffer
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-COMMAND_HANDLER(psoc6_handle_mass_erase_command)
+static int psoc6_program_with_algo(struct flash_bank *bank, const uint8_t 
*buffer,
+       uint32_t offset, uint32_t count)
 {
-       if (CMD_ARGC != 1)
-               return ERROR_COMMAND_SYNTAX_ERROR;
+       struct target *target = bank->target;
+       struct psoc6_bank_info *info = bank->driver_priv;
+       int hr;
 
-       struct flash_bank *bank;
-       int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       const size_t algo_size = info->program_algo_size;
+       const uint8_t *algo_p = info->program_algo_p;
+
+       struct working_area *wa_algorithm;
+       struct working_area *wa_stack;
+       struct working_area *wa_buffer;
+
+       if (info->prepare_function) {
+               hr = info->prepare_function(bank);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       /* Allocate buffer for the algorithm */
+       hr = target_alloc_working_area(target, algo_size, &wa_algorithm);
        if (hr != ERROR_OK)
                return hr;
 
-       hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
+       /* Write the algorithm code */
+       hr = target_write_buffer(target, wa_algorithm->address, algo_size, 
algo_p);
+       if (hr != ERROR_OK)
+               goto err_free_wa_algo;
+
+       /* Allocate buffer for the stack */
+       hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &wa_stack);
+       if (hr != ERROR_OK)
+               goto err_free_wa_algo;
+
+       /* Try to allocate as large RAM Buffer as possible */
+       const uint32_t wa_avail = target_get_working_area_avail(target);
+       uint32_t num_rows = (wa_avail - 8) / info->page_size;
+       if (num_rows <= 4) {
+               LOG_WARNING("Failed to allocate Circular Buffer, falling back 
to DAP mode");
+               hr = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto err_free_wa_stack;
+       }
+
+       hr = target_alloc_working_area(target, num_rows * info->page_size + 8, 
&wa_buffer);
+       assert(hr == ERROR_OK);
+
+       LOG_DEBUG("Allocated buffer for %d pages (%d bytes)", num_rows, 
num_rows * info->page_size);
+
+       struct armv7m_algorithm armv7m_algo;
+       armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_algo.core_mode = ARM_MODE_THREAD;
+
+       struct reg_param reg_params[5];
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+       init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);
+
+       buf_set_u32(reg_params[0].value, 0, 32, wa_buffer->address);
+       buf_set_u32(reg_params[1].value, 0, 32, wa_buffer->address + 
wa_buffer->size);
+       buf_set_u32(reg_params[2].value, 0, 32, bank->base + offset);
+       buf_set_u32(reg_params[3].value, 0, 32, count / info->page_size);
+       buf_set_u32(reg_params[4].value, 0, 32, wa_stack->address + 
wa_stack->size);
+
+       hr = target_run_flash_async_algorithm(target, buffer, count / 
info->page_size,
+                       info->page_size, 0, NULL, ARRAY_SIZE(reg_params), 
reg_params,
+                       wa_buffer->address, wa_buffer->size,
+                       wa_algorithm->address, 0, &armv7m_algo);
+
+       if (hr != ERROR_OK) {
+               uint32_t srom_result = buf_get_u32(reg_params[0].value, 0, 32);
+               if ((srom_result & SROMAPI_STATUS_MSK) != SROMAPI_STAT_SUCCESS) 
{
+                       LOG_ERROR("SROM API execution failed. Status: 0x%08X", 
srom_result);
+                       hr = ERROR_FAIL;
+               }
+       }
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+
+       target_free_working_area(target, wa_buffer);
+
+err_free_wa_stack:
+       target_free_working_area(target, wa_stack);
+
+err_free_wa_algo:
+       target_free_working_area(target, wa_algorithm);
 
        return hr;
 }
 
+static bool psoc6_is_address_bootable(uint32_t variant, target_addr_t addr)
+{
+       switch (variant) {
+       case PSOC6_VARIANT_PSOC6_BLE2:
+       case PSOC6_VARIANT_PSOC6A_2M:
+               return  (addr >= 0x10000000 && addr < 0x10200000) || /* Main 
Flash, 2 MiB max */
+                               (addr >= 0x08000000 && addr < 0x08100000) || /* 
RAM, 1 MiB max */
+                               (addr >= 0x18000000 && addr < 0x20000000);   /* 
XIP, 128 MiB max */
+
+       default:
+               LOG_WARNING("Unsupported PSoC6 variant: %" PRIu32 ", reset_halt 
may fail", variant);
+               return true;
+       }
+}
+
 /** 
***********************************************************************************************
  * @brief Simulates broken Vector Catch
  * Function will try to determine entry point of user application. If it 
succeeds it will set HW
@@ -881,129 +1503,596 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command)
  * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 
core.
  *
  * @param target current target
+ * @param mode overrides default reset type for the core
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
-static int handle_reset_halt(struct target *target)
+static int psoc6_reset_halt(struct target *target, enum reset_halt_mode mode)
 {
+       const struct psoc6_bank_info *info = 
psoc6_get_bank_info_by_target(target);
+       if (!info) {
+               LOG_ERROR("Unable to locate psoc6_bank_info structure for 
target %s",
+                       target->cmd_name);
+               return ERROR_FAIL;
+       }
+
        int hr;
+       const long timeout_ms = (target->coreid == 0) ? CM0_VTOR_TIMEOUT_MS : 
OTHER_VTOR_TIMEOUT_MS;
+       LOG_INFO("%s: Waiting up to %ld.%ld sec for valid Vector Table 
address...",
+                        target_name(target), timeout_ms / 1000u, timeout_ms % 
1000u);
+
+       uint32_t vt_base;
        uint32_t reset_addr;
-       bool is_cm0 = (target->coreid == 0);
+       bool vt_found = false;
+       struct timeout to;
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       psoc6_timeout_init(&to, timeout_ms);
+       while (!psoc6_timeout_expired(&to)) {
+               keep_alive();
 
-       /* Halt target device */
-       if (target->state != TARGET_HALTED) {
-               hr = target_halt(target);
+               /* Read Vector Table Offset register */
+               hr = mem_ap_read_atomic_u32(armv7m->debug_ap, 
info->regs->vtbase[target->coreid], &vt_base);
                if (hr != ERROR_OK)
-                       return hr;
+                       continue;
 
-               target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
-               if (hr != ERROR_OK)
-                       return hr;
-       }
+               if (target->coreid == 0 && (vt_base & 0xFFFF0000) == 
0xFFFF0000) {
+                       LOG_INFO("%s: Application is invalid (VTOR = 0x%08X), 
reset_halt skipped",
+                                        target_name(target), vt_base);
+                       goto exit_halt_cpu;
+               }
 
-       /* Read Vector Offset register */
-       uint32_t vt_base;
-       const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
-       hr = target_read_u32(target, vt_offset_reg, &vt_base);
-       if (hr != ERROR_OK)
-               return ERROR_OK;
+               /* Vector Table Offset must point to bootable region */
+               if (!psoc6_is_address_bootable(info->regs->variant, vt_base))
+                       continue;
 
-       /* Invalid value means flash is empty */
-       vt_base &= 0xFFFFFF00;
-       if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
-               return ERROR_OK;
+               /* Read Reset_Handler address */
+               hr = mem_ap_read_atomic_u32(armv7m->debug_ap, vt_base + 4, 
&reset_addr);
+               if (hr != ERROR_OK)
+                       continue;
 
-       /* Read Reset Vector value*/
-       hr = target_read_u32(target, vt_base + 4, &reset_addr);
-       if (hr != ERROR_OK)
-               return hr;
+               /* Read Reset_Handler must belong to bootable region */
+               if (psoc6_is_address_bootable(info->regs->variant, reset_addr)) 
{
+                       vt_found = true;
+                       break;
+               }
+       }
 
-       /* Invalid value means flash is empty */
-       if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
-               return ERROR_OK;
+       if (!vt_found) {
+               LOG_INFO("%s: Vector Table not found (core not started?), 
reset_halt skipped", target_name(target));
+               goto exit_halt_cpu;
+       }
 
+       LOG_INFO("%s: Vector Table found at 0x%08X", target_name(target), 
vt_base);
 
        /* Set breakpoint at User Application entry point */
        hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD);
        if (hr != ERROR_OK)
                return hr;
 
-       const struct armv7m_common *cm = target_to_armv7m(target);
-
-       /* PSoC6 reboots immediately after issuing SYSRESETREQ / VECTRESET
+       /* PSoC6 platform reboots immediately after issuing SYSRESETREQ / 
VECTRESET
         * this disables SWD/JTAG pins momentarily and may break communication
         * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here 
*/
-       if (is_cm0) {
-               /* Reset the CM0 by asserting SYSRESETREQ. This will also reset 
CM4 */
-               LOG_INFO("psoc6.cm0: bkpt @0x%08" PRIX32 ", issuing 
SYSRESETREQ", reset_addr);
-               mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
-                       AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
+
+       char *mode_str = "SYSRESETREQ";
+       uint32_t rst_mask = AIRCR_SYSRESETREQ;
+
+       if (mode == mode_default) {
+               if (target->coreid) {
+                       mode_str = "VECTRESET";
+                       rst_mask = AIRCR_VECTRESET;
+               }
+       } else if (mode == mode_vectreset) {
+               mode_str = "VECTRESET";
+               rst_mask = AIRCR_VECTRESET;
+       }
+
+       /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
+       LOG_INFO("%s: bkpt @0x%08X, issuing %s", target_name(target), 
reset_addr, mode_str);
+
+       /* Workaround for PT-2019, both cores enter LOCKUP state with slow JTAG 
clock
+        * This happens probably because JTAG pins gets disconnected 
momentarily when
+        * SYSRESETREQ bit is written causing invalid JTAG state when pins gets 
connected
+        * back to the DAP by the boot code. */
+#if (0)
+       mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_AIRCR,
+               AIRCR_VECTKEY | rst_mask);
+#else
+       mem_ap_write_u32(armv7m->debug_ap, NVIC_AIRCR, AIRCR_VECTKEY | 
rst_mask);
+       struct adiv5_dap *dap = armv7m->debug_ap->dap;
+       if (dap->ops->sync) {
+               dap->ops->sync(dap);
        } else {
-               LOG_INFO("psoc6.cm4: bkpt @0x%08" PRIX32 ", issuing VECTRESET", 
reset_addr);
-               mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
-                       AIRCR_VECTKEY | AIRCR_VECTRESET);
+               /* SWD DAP does not support sync() method, use run() instead */
+               dap->ops->run(dap);
        }
+#endif
+
+       jtag_sleep(jtag_get_nsrst_delay() * 1000u);
 
-       /* Wait 100ms for bootcode and reinitialize DAP */
-       usleep(100000);
-       dap_dp_init(cm->debug_ap->dap);
+       /* Target is now under RESET */
+       target->state = TARGET_RESET;
+
+       /* Register cache is now invalid */
+       register_cache_invalidate(target->reg_cache);
+
+       /* Wait for debug interface to be ready */
+       psoc6_timeout_init(&to, IPC_TIMEOUT_MS);
+       while (!psoc6_timeout_expired(&to)) {
+               if (dap_dp_init(armv7m->debug_ap->dap) != ERROR_OK ||
+                       target_examine_one(target) != ERROR_OK           ||
+                       target_poll(target) != ERROR_OK)
+                       continue;
+               break;
+       }
 
+       /* Finally wait for the target to halt on break point */
        target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
 
        /* Remove the break point */
        breakpoint_remove(target, reset_addr);
 
+       /* Wipe-out previous RTOS state, if any */
+       //if (target->rtos_wipe_on_reset_halt)
+       //      rtos_wipe(target);
+
        return ERROR_OK;
+
+exit_halt_cpu:
+       hr = target_poll(target);
+       if (hr != ERROR_OK)
+               return hr;
+
+       /* Poll again if we came here right from Reset
+        * or target_halt() will not skip writing C_HALT bit */
+       if (target->state == TARGET_RESET) {
+               hr = target_poll(target);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       /* Halt the target if it is running */
+       if (target->state == TARGET_RUNNING) {
+               hr = target_halt(target);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               hr = target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+
+       return hr;
 }
 
 /** 
***********************************************************************************************
- * @brief Simulates broken Vector Catch
- * Function will try to determine entry point of user application. If it 
succeeds it will set HW
- * breakpoint at that address, issue SW Reset and remove the breakpoint 
afterwards.
- * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. 
Boot code will
- * reset CM4 anyway, so using SYSRESETREQ is safe here.
- * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 
core.
- *
+ * @brief Performs Mass Erase operation
+ * @param bank flash bank index to erase
  * @return ERROR_OK in case of success, ERROR_XXX code otherwise
  
*************************************************************************************************/
+COMMAND_HANDLER(psoc6_handle_mass_erase_command)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (hr != ERROR_OK)
+               return hr;
+
+       hr = flash_driver_erase(bank, 0, bank->num_sectors - 1);
+       return hr;
+}
+
 COMMAND_HANDLER(psoc6_handle_reset_halt)
 {
-       if (CMD_ARGC)
+       enum reset_halt_mode mode;
+
+       if (CMD_ARGC == 0) {
+               mode = mode_default;
+       } else if (CMD_ARGC == 1) {
+               if (strcmp(CMD_ARGV[0], "sysresetreq") == 0)
+                       mode = mode_sysresetreq;
+               else if (strcmp(CMD_ARGV[0], "vectreset") == 0)
+                       mode = mode_vectreset;
+               else if (strcmp(CMD_ARGV[0], "default") == 0)
+                       mode = mode_default;
+               else
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+       } else {
                return ERROR_COMMAND_SYNTAX_ERROR;
+       }
 
        struct target *target = get_current_target(CMD_CTX);
-       return handle_reset_halt(target);
+       return psoc6_reset_halt(target, mode);
 }
 
-FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
+COMMAND_HANDLER(psoc6_handle_sflash_restrictions)
 {
-       struct psoc6_target_info *psoc6_info;
-       int hr = ERROR_OK;
+       uint32_t restrictions;
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
 
-       if (CMD_ARGC < 6)
-               hr = ERROR_COMMAND_SYNTAX_ERROR;
-       else {
-               psoc6_info = calloc(1, sizeof(struct psoc6_target_info));
-               psoc6_info->is_probed = false;
-               bank->driver_priv = psoc6_info;
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], restrictions);
+       if (restrictions > 3) {
+               LOG_ERROR("SFlash restriction level should be in range 0...3");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       g_sflash_restrictions = restrictions;
+
+       if (g_sflash_restrictions)
+               LOG_WARNING("SFlash programming allowed for regions: %s",
+                                       g_sflash_restrictions == 1 ? "USER, 
TOC, KEY" :
+                                       g_sflash_restrictions == 2 ? "USER, 
TOC, KEY, NAR" :
+                                                                               
                 "Whole SFlash region");
+       else
+               LOG_INFO("SFlash programming disallowed, see 
'sflash_restrictions' command");
+
+       return ERROR_OK;
+}
+
+/** 
***********************************************************************************************
+ * @brief Deallocates private driver structures
+ * @param bank - the bank being destroyed
+ 
*************************************************************************************************/
+void psoc6_free_driver_priv(struct flash_bank *bank)
+{
+       free(bank->driver_priv);
+       bank->driver_priv = NULL;
+}
+
+COMMAND_HANDLER(psoc6_handle_set_region_size)
+{
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       uint32_t sectors = 0;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], sectors);
+
+       struct flash_bank *bank = get_flash_bank_by_name_noprobe(CMD_ARGV[0]);
+       if (!bank) {
+               LOG_ERROR("Invalid Flash Bank for psoc6_handle_set_region_size: 
%s", CMD_ARGV[0]);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct psoc6_bank_info *info = bank->driver_priv;
+       info->size_override = sectors;
+
+       return ERROR_OK;
+}
+
+static struct flash_bank *psoc6_get_any_bank(struct target *target)
+{
+       for (struct flash_bank *b = flash_bank_list(); b; b = b->next) {
+               if (b->target == target) {
+                       b->driver->auto_probe(b);
+                       return b;
+               }
+       }
+
+       LOG_ERROR("Unable to find ant flash bank for the target %s", 
target_name(target));
+       return NULL;
+}
+
+COMMAND_HANDLER(psoc6_handle_sromcall_prepare)
+{
+       if (g_sromcall_prepare_called) {
+               LOG_ERROR("SROM Call: prepare/release not in sequence");
+               return ERROR_FAIL;
+       }
+
+       g_sromcall_prepare_called = true;
+       struct flash_bank *bank = 
psoc6_get_any_bank(get_current_target(CMD_CTX));
+       if (!bank)
+               return ERROR_FAIL;
+
+       return psoc6_sromalgo_prepare(bank);
+}
+
+COMMAND_HANDLER(psoc6_handle_sromcall)
+{
+       if (!CMD_ARGC) {
+               LOG_ERROR("At least one argument required");
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
+
+       uint32_t sromapi_params[CMD_ARGC];
+
+       for (size_t i = 0; i < CMD_ARGC; i++) {
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i], sromapi_params[i]);
+               if (i == 0 && (sromapi_params[i] & 0x01) && CMD_ARGC > 1) {
+                       LOG_ERROR("Additional SROM API parameters can be passed 
via RAM buffer only, "
+                                         "check bit #0 of your SROM API 
request.");
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+       }
+
+       struct target *target = get_current_target(CMD_CTX);
+       struct working_area *wa = NULL;
+
+       int hr;
+       bool data_in_ram = (sromapi_params[0] & SROMAPI_DATA_LOCATION_MSK) == 0;
+
+       if (data_in_ram) {
+               hr = target_alloc_working_area(target, CMD_ARGC * 
sizeof(uint32_t), &wa);
+               if (hr != ERROR_OK)
+                       goto exit;
+
+               hr = target_write_buffer(target, wa->address, CMD_ARGC * 
sizeof(uint32_t), (uint8_t *)sromapi_params);
+               if (hr != ERROR_OK)
+                       goto exit_free_wa;
+       }
+
+       struct flash_bank *bank = 
psoc6_get_any_bank(get_current_target(CMD_CTX));
+       if (!bank) {
+               hr = ERROR_FAIL;
+               goto exit_free_wa;
+       }
+
+       uint32_t data_out;
+       hr = psoc6_call_sromapi(bank, sromapi_params[0], wa ? wa->address : 0, 
&data_out);
+       if (hr == ERROR_OK && data_out != 0xA0000000)
+               command_print(CMD, "0x%08X", data_out);
+
+exit_free_wa:
+       if (data_in_ram)
+               target_free_working_area(target, wa);
+
+exit:
        return hr;
 }
 
-static const struct command_registration psoc6_exec_command_handlers[] = {
+COMMAND_HANDLER(psoc6_handle_sromcall_release)
+{
+       if (!g_sromcall_prepare_called) {
+               LOG_ERROR("SROM Call: prepare/release not in sequence");
+               return ERROR_FAIL;
+       }
+
+       psoc6_sromalgo_release(get_current_target(CMD_CTX));
+       g_sromcall_prepare_called = false;
+       return ERROR_OK;
+}
+
+/** 
***********************************************************************************************
+ * @brief Dummy function, device does not support flash bank protection
+ * @return ERROR_OK always
+ 
*************************************************************************************************/
+static int dummy_protect(struct flash_bank *bank, int set, unsigned int first, 
unsigned int last)
+{
+       (void)bank; (void)set; (void)first; (void)last;
+
+       LOG_WARNING("Device does not support flash bank protection");
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(psoc6_ble2_flash_bank_command)
+{
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       static const uint8_t p6_program_algo[] = {
+               #include "../../../contrib/loaders/flash/psoc6/psoc6_write.inc"
+       };
+
+       static const uint8_t p6_erase_algo[] = {
+               #include "../../../contrib/loaders/flash/psoc6/psoc6_erase.inc"
+       };
+
+       struct psoc6_bank_info *info = calloc(1, sizeof(struct 
psoc6_bank_info));
+       info->program_algo_p = p6_program_algo;
+       info->program_algo_size = sizeof(p6_program_algo);
+       info->erase_algo_p = p6_erase_algo;
+       info->erase_algo_size = sizeof(p6_erase_algo);
+       info->regs = &psoc6_ble2_regs;
+       info->sflash_regions = psoc6_safe_sflash_regions;
+       info->size_override = bank->size;
+       bank->driver_priv = info;
+
+       return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(psoc6_2m_flash_bank_command)
+{
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       static const uint8_t p6_2m_program_algo[] = {
+               #include 
"../../../contrib/loaders/flash/psoc6/psoc62m_write.inc"
+       };
+
+       static const uint8_t p6_2m_erase_algo[] = {
+               #include 
"../../../contrib/loaders/flash/psoc6/psoc62m_erase.inc"
+       };
+
+       struct psoc6_bank_info *info = calloc(1, sizeof(struct 
psoc6_bank_info));
+       info->program_algo_p = p6_2m_program_algo;
+       info->program_algo_size = sizeof(p6_2m_program_algo);
+       info->erase_algo_p = p6_2m_erase_algo;
+       info->erase_algo_size = sizeof(p6_2m_erase_algo);
+       info->regs = &psoc6_2m_regs;
+       info->sflash_regions = psoc6_safe_sflash_regions;
+       info->size_override = bank->size;
+       bank->driver_priv = info;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(psoc6_handle_secure_acquire)
+{
+       int hr;
+       struct timeout to;
+       struct target *target = get_current_target(CMD_CTX);
+       uint32_t ap = target->coreid == 0xFF ? 0 : target_to_cm(target)->apsel;
+       bool acquire_mode_halt;
+       bool do_handshake;
+
+       if (CMD_ARGC != 4)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       uint32_t magic_addr;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], magic_addr);
+
+       if (strcmp(CMD_ARGV[1], "run") == 0) {
+               acquire_mode_halt = false;
+       } else if (strcmp(CMD_ARGV[1], "halt") == 0) {
+               acquire_mode_halt = true;
+       } else {
+               LOG_ERROR("Invalid mode for secure_acquire: '%s'. "
+                                 "Only 'run' and 'halt' are currently 
supported.", CMD_ARGV[1]);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (strcmp(CMD_ARGV[2], "handshake") == 0) {
+               do_handshake = true;
+       } else if (strcmp(CMD_ARGV[2], "no_handshake") == 0) {
+               do_handshake = false;
+       } else {
+               LOG_ERROR("Invalid handshake mode for secure_acquire: '%s'. "
+                                 "Only 'handshake' and 'no_handshake' are 
currently supported.", CMD_ARGV[2]);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       uint32_t timeout;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], timeout);
+
+       LOG_INFO("Waiting up to %d.%d sec for the bootloader to open AP #%d...",
+                        timeout / 1000u, timeout % 1000u, ap);
+
+       //const enum log_levels old_level = change_debug_level(LOG_LVL_USER);
+       psoc6_timeout_init(&to, timeout);
+
+       const char *error_msg = "";
+
+       /* Wait for boot code to open corresponding AP */
+       while (!psoc6_timeout_expired(&to)) {
+               keep_alive();
+
+               error_msg = "Failed to access debug sybsystem";
+               target->examined = false;
+               if (target_examine_one(target) == ERROR_OK)
+                       break;
+       };
+
+       /* Set TEST_MODE bit (only if we are going to halt) */
+       while (do_handshake && acquire_mode_halt && 
!psoc6_timeout_expired(&to)) {
+               keep_alive();
+
+               error_msg = "failed to write SRSS.TST_MODE register";
+               if (target_write_u32(target, 0x40260100, 0x80000000) != 
ERROR_OK)
+                       continue;
+
+               error_msg = "";
+               break;
+       };
+       //change_debug_level(old_level);
+
+       if (psoc6_timeout_expired(&to)) {
+               LOG_ERROR("AP #%d is still not opened: %s, giving up", ap, 
error_msg);
+               return ERROR_TARGET_FAILURE;
+       }
+
+       /* Wait for handshake (only if we are going to halt) */
+       if (do_handshake && acquire_mode_halt) {
+               LOG_INFO("Waiting up to %d.%d sec for the handshake from the 
target...",
+                                timeout / 1000u, timeout % 1000u);
+
+               //change_debug_level(LOG_LVL_USER);
+               psoc6_timeout_init(&to, timeout);
+               while (!psoc6_timeout_expired(&to)) {
+                       keep_alive();
+
+                       uint32_t ipc_data;
+                       if (target_read_u32(target, magic_addr, &ipc_data) != 
ERROR_OK)
+                               continue;
+
+                       if (ipc_data == 0x12344321)
+                               break;
+               };
+               //change_debug_level(old_level);
+
+               if (psoc6_timeout_expired(&to))
+                       LOG_WARNING("No handshake from the target, continuing 
anyway");
+       }
+
+       hr = target_poll(target);
+       if (hr != ERROR_OK)
+               return hr;
+
+       hr = target_poll(target);
+       if (hr != ERROR_OK)
+               return hr;
+
+       /* Halt the target, if requested */
+       if (acquire_mode_halt) {
+               hr = target_halt(target);
+               if (hr != ERROR_OK)
+                       return hr;
+
+               hr = target_wait_state(target, TARGET_HALTED, 1000);
+               if (hr != ERROR_OK)
+                       return hr;
+       }
+       return ERROR_OK;
+}
+
+const struct command_registration psoc6_exec_command_handlers[] = {
        {
                .name = "mass_erase",
                .handler = psoc6_handle_mass_erase_command,
                .mode = COMMAND_EXEC,
-               .usage = "bank",
-               .help = "Erases entire Main Flash",
+               .usage = "<bank>",
+               .help = "Erases entire flash bank",
        },
        {
                .name = "reset_halt",
                .handler = psoc6_handle_reset_halt,
                .mode = COMMAND_EXEC,
-               .usage = "",
+               .usage = "[mode (sysresetreq, vectreset), by default 
core-dependent reset is used]",
                .help = "Tries to simulate broken Vector Catch",
        },
+       {
+               .name = "sflash_restrictions",
+               .handler = psoc6_handle_sflash_restrictions,
+               .mode = COMMAND_ANY,
+               .usage = "<0|1|2|3>",
+               .help = "Controls SFlash programming restrictions: 0:Writes 
disallowed, "
+                               "1:USER+TOC+KEY, 2:USER+TOC+KEY+NAR, 3:Whole 
region",
+       },
+       {
+               .name = "set_region_size",
+               .handler = psoc6_handle_set_region_size,
+               .mode = COMMAND_ANY,
+               .usage = "<region_name> <region_sectors>",
+               .help = "Sets sectors for specified region",
+       },
+       {
+               .name = "sromcall_prepare",
+               .handler = psoc6_handle_sromcall_prepare,
+               .mode = COMMAND_ANY,
+               .usage = "",
+               .help = "Prepares psoc6 driver for direct srom calls",
+       },
+       {
+               .name = "sromcall",
+               .handler = psoc6_handle_sromcall,
+               .mode = COMMAND_ANY,
+               .usage = "<call_id> [param1] [param2] ...",
+               .help = "Calls SROM API function <call_id> with arbitrary 
number of additional parameters",
+       },
+       {
+               .name = "sromcall_release",
+               .handler = psoc6_handle_sromcall_release,
+               .mode = COMMAND_ANY,
+               .usage = "",
+               .help = "Releases resources allocated by 'sromcall_prepare'",
+       },
+       {
+               .name = "secure_acquire",
+               .handler = psoc6_handle_secure_acquire,
+               .mode = COMMAND_EXEC,
+               .usage = "<psoc6|psoc6_2m> <run|halt> <handshake|no_handshake> 
<timeout>",
+               .help = "",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -1018,12 +2107,30 @@ static const struct command_registration 
psoc6_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
+/* Flash driver for PSoC6 BLE2 */
 const struct flash_driver psoc6_flash = {
        .name = "psoc6",
        .commands = psoc6_command_handlers,
-       .flash_bank_command = psoc6_flash_bank_command,
+       .flash_bank_command = psoc6_ble2_flash_bank_command,
+       .erase = psoc6_erase,
+       .protect = dummy_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,
+       .free_driver_priv = psoc6_free_driver_priv,
+};
+
+/* Flash driver for PSoC6 BLE2 */
+struct flash_driver psoc6_2m_flash = {
+       .name = "psoc6_2m",
+       .commands = psoc6_command_handlers,
+       .flash_bank_command = psoc6_2m_flash_bank_command,
        .erase = psoc6_erase,
-       .protect = psoc6_protect,
+       .protect = dummy_protect,
        .write = psoc6_program,
        .read = default_flash_read,
        .probe = psoc6_probe,
@@ -1031,5 +2138,5 @@ const struct flash_driver psoc6_flash = {
        .erase_check = default_flash_blank_check,
        .protect_check = psoc6_protect_check,
        .info = psoc6_get_info,
-       .free_driver_priv = default_flash_free_driver_priv,
+       .free_driver_priv = psoc6_free_driver_priv,
 };

-- 

Reply via email to