openocd: fix SPDX tag format for files .c
[fw/openocd] / src / flash / nor / psoc4.c
index 182745036e9ac5ccc0d0804177811f14811f6c8d..c935bd5f29167539a35f222b276bccc680e7373f 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
  *   Copyright (C) 2014 by Tomas Vanek (PSoC 4 support derived from STM32) *
  *   vanekt@fbl.cz                                                         *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 #include <target/algorithm.h>
 #include <target/armv7m.h>
 
-/* device documets:
+/* device documents:
 
  PSoC(R) 4: PSoC 4200 Family Datasheet
        Document Number: 001-87197 Rev. *B  Revised August 29, 2013
 
  PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM
-       Document No. 001-85634 Rev. *C March 25, 2014
+       Document No. 001-85634 Rev. *E June 28, 2016
 
  PSoC(R) 4 Registers TRM Spec.
        Document No. 001-85847 Rev. *A June 25, 2013
 
+ PSoC 4000 Family PSoC(R) 4 Technical Reference Manual
+       Document No. 001-89309 Rev. *B May 9, 2016
+
+ PSoC 41XX_BLE/42XX_BLE Family PSoC 4 BLE Architecture TRM
+       Document No. 001-92738 Rev. *C February 12, 2016
+
+ PSoC 4200L Family PSoC 4 Architecture TRM
+       Document No. 001-97952 Rev. *A December 15, 2015
+
+ PSoC 4200L Family PSoC 4 Registers TRM
+       Document No. 001-98126 Rev. *A December 16, 2015
+
+ PSoC 4100M/4200M Family PSoC 4 Architecture TRM
+       Document No. 001-95223 Rev. *B July 29, 2015
+
+ PSoC 4100S Family PSoC 4 Architecture TRM
+       Document No. 002-10621 Rev. *A July 29, 2016
+
+ PSoC 4100S Family PSoC 4 Registers TRM
+       Document No. 002-10523 Rev. *A July 20, 2016
+
+ PSoC Analog Coprocessor Architecture TRM
+       Document No. 002-10404 Rev. ** December 18, 2015
+
+ CY8C4Axx PSoC Analog Coprocessor Registers TRM
+       Document No. 002-10405 Rev. ** December 18, 2015
+
  CY8C41xx, CY8C42xx Programming Specifications
        Document No. 001-81799 Rev. *C March 4, 2014
+
+ CYBL10x6x, CY8C4127_BL, CY8C4247_BL Programming Specifications
+       Document No. 001-91508 Rev. *B September 22, 2014
+
+ http://dmitry.gr/index.php?r=05.Projects&proj=24.%20PSoC4%20confidential
 */
 
 /* register locations */
-#define PSOC4_CPUSS_SYSREQ     0x40000004
-#define PSOC4_CPUSS_SYSARG     0x40000008
-#define PSOC4_TEST_MODE                0x40030014
-#define PSOC4_SPCIF_GEOMETRY   0x400E0000
+#define PSOC4_SFLASH_MACRO0            0x0FFFF000
+
+#define PSOC4_CPUSS_SYSREQ_LEGACY      0x40000004
+#define PSOC4_CPUSS_SYSARG_LEGACY      0x40000008
+#define PSOC4_SPCIF_GEOMETRY_LEGACY    0x400E0000
+
+#define PSOC4_CPUSS_SYSREQ_NEW         0x40100004
+#define PSOC4_CPUSS_SYSARG_NEW         0x40100008
+#define PSOC4_SPCIF_GEOMETRY_NEW       0x40110000
+
+#define PSOC4_TEST_MODE                        0x40030014
+
+#define PSOC4_ROMTABLE_PID0            0xF0000FE0
 
-#define PSOC4_SFLASH_MACRO     0x0ffff000
 
 /* constants */
+#define PSOC4_SFLASH_MACRO_SIZE                0x800
+#define PSOC4_ROWS_PER_MACRO           512
+
 #define PSOC4_SROM_KEY1                        0xb6
 #define PSOC4_SROM_KEY2                        0xd3
 #define PSOC4_SROM_SYSREQ_BIT          (1<<31)
 #define PSOC4_SROM_PRIVILEGED_BIT      (1<<28)
 #define PSOC4_SROM_STATUS_SUCCEEDED    0xa0000000
 #define PSOC4_SROM_STATUS_FAILED       0xf0000000
+#define PSOC4_SROM_STATUS_MASK         0xf0000000
+
+/* not documented in any TRM */
+#define PSOC4_SROM_ERR_IMO_NOT_IMPLEM  0xf0000013
 
 #define PSOC4_CMD_GET_SILICON_ID       0
 #define PSOC4_CMD_LOAD_LATCH           4
 #define PSOC4_CMD_ERASE_ALL            0xa
 #define PSOC4_CMD_CHECKSUM             0xb
 #define PSOC4_CMD_WRITE_PROTECTION     0xd
+#define PSOC4_CMD_SET_IMO48            0x15
+#define PSOC4_CMD_WRITE_SFLASH_ROW     0x18
 
 #define PSOC4_CHIP_PROT_VIRGIN         0x0
 #define PSOC4_CHIP_PROT_OPEN           0x1
 #define PSOC4_CHIP_PROT_PROTECTED      0x2
 #define PSOC4_CHIP_PROT_KILL           0x4
 
+#define PSOC4_ROMTABLE_DESIGNER_CHECK  0xb4
+
+#define PSOC4_FAMILY_FLAG_LEGACY       1
 
-struct psoc4_chip_details {
+struct psoc4_chip_family {
        uint16_t id;
-       const char *type;
-       const char *package;
-       uint32_t flash_size_in_kb;
+       const char *name;
+       uint32_t flags;
 };
 
-/* list of PSoC 4 chips
- * flash_size_in_kb is not necessary as it can be decoded from SPCIF_GEOMETRY
- */
-const struct psoc4_chip_details psoc4_devices[] = {
-       /* 4200 series */
-       { 0x04A6, "CY8C4245PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
-       { 0x04B6, "CY8C4245LQI-483", "QFN-40",  .flash_size_in_kb = 32 },
-       { 0x04C8, "CY8C4245AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
-       { 0x04FB, "CY8C4245AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
-       { 0x04F0, "CY8C4244PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
-       { 0x04F1, "CY8C4244PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
-       { 0x04F6, "CY8C4244LQI-443", "QFN-40",  .flash_size_in_kb = 16 },
-       { 0x04FA, "CY8C4244AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
-
-       /* 4100 series */
-       { 0x0410, "CY8C4124PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
-       { 0x0411, "CY8C4124PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
-       { 0x0416, "CY8C4124LQI-443", "QFN-40",  .flash_size_in_kb = 16 },
-       { 0x041A, "CY8C4124AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
-       { 0x041B, "CY8C4125AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
-       { 0x0412, "CY8C4125PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
-       { 0x0417, "CY8C4125LQI-483", "QFN-40",  .flash_size_in_kb = 32 },
-       { 0x041C, "CY8C4125AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
-
-       /* CCG1 series */
-       { 0x0490, "CYPD1103-35FNXI", "CSP-35",  .flash_size_in_kb = 32 },
-       { 0x0489, "CYPD1121-40LQXI", "QFN-40",  .flash_size_in_kb = 32 },
-       { 0x048A, "CYPD1122-40LQXI", "QFN-40",  .flash_size_in_kb = 32 },
-       { 0x0491, "CYPD1131-35FNXI", "CSP-35",  .flash_size_in_kb = 32 },
-       { 0x0498, "CYPD1132-16SXI",  "SOIC-16", .flash_size_in_kb = 32 },
-       { 0x0481, "CYPD1134-28PVXI", "SSOP-28", .flash_size_in_kb = 32 },
-       { 0x048B, "CYPD1134-40LQXI", "QFN-40",  .flash_size_in_kb = 32 },
+static const struct psoc4_chip_family psoc4_families[] = {
+       { 0x93, "PSoC4100/4200",           .flags = PSOC4_FAMILY_FLAG_LEGACY },
+       { 0x9A, "PSoC4000",                .flags = 0 },
+       { 0x9E, "PSoC/PRoC BLE (119E)",    .flags = 0 },
+       { 0xA0, "PSoC4200L",               .flags = 0 },
+       { 0xA1, "PSoC4100M/4200M",         .flags = 0 },
+       { 0xA3, "PSoC/PRoC BLE (11A3)",    .flags = 0 },
+       { 0xA9, "PSoC4000S",               .flags = 0 },
+       { 0xAA, "PSoC/PRoC BLE (11AA)",    .flags = 0 },
+       { 0xAB, "PSoC4100S",               .flags = 0 },
+       { 0xAC, "PSoC Analog Coprocessor", .flags = 0 },
+       { 0,    "Unknown",                 .flags = 0 }
 };
 
 
 struct psoc4_flash_bank {
        uint32_t row_size;
        uint32_t user_bank_size;
-       int probed;
-       uint32_t silicon_id;
-       uint8_t chip_protection;
+       unsigned int num_macros;
+       bool probed;
        uint8_t cmd_program_row;
+       uint16_t family_id;
+       bool legacy_family;
+       uint32_t cpuss_sysreq_addr;
+       uint32_t cpuss_sysarg_addr;
+       uint32_t spcif_geometry_addr;
 };
 
 
-static const struct psoc4_chip_details *psoc4_details_by_id(uint32_t silicon_id)
+static const struct psoc4_chip_family *psoc4_family_by_id(uint16_t family_id)
 {
-       const struct psoc4_chip_details *p = psoc4_devices;
-       unsigned int i;
-       uint16_t id = silicon_id >> 16; /* ignore die revision */
-       for (i = 0; i < sizeof(psoc4_devices)/sizeof(psoc4_devices[0]); i++, p++) {
-               if (p->id == id)
-                       return p;
-       }
-       LOG_DEBUG("Unknown PSoC 4 device silicon id 0x%08" PRIx32 ".", silicon_id);
-       return NULL;
+       const struct psoc4_chip_family *p = psoc4_families;
+       while (p->id && p->id != family_id)
+               p++;
+
+       return p;
 }
 
 static const char *psoc4_decode_chip_protection(uint8_t protection)
@@ -173,7 +196,9 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
        psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank));
 
        bank->driver_priv = psoc4_info;
+       bank->default_padded_value = bank->erased_value = 0x00;
        psoc4_info->user_bank_size = bank->size;
+       psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW;
 
        return ERROR_OK;
 }
@@ -186,9 +211,14 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
  *  Otherwise address of memory parameter block is set in CPUSS_SYSARG
  *  and the first parameter is written to the first word of parameter block
  */
-static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
-               uint32_t *sysreq_params, uint32_t sysreq_params_size)
+static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd,
+               uint16_t cmd_param,
+               uint32_t *sysreq_params, uint32_t sysreq_params_size,
+               uint32_t *sysarg_out)
 {
+       struct target *target = bank->target;
+       struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
+
        struct working_area *sysreq_wait_algorithm;
        struct working_area *sysreq_mem;
 
@@ -209,8 +239,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
 
        const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4;
                                        /* stack must be aligned */
-       const int stack_size = 196;
-       /* tested stack sizes on PSoC 4:
+       const int stack_size = 256;
+       /* tested stack sizes on PSoC4200:
                ERASE_ALL       144
                PROGRAM_ROW     112
                other sysreq     68
@@ -235,6 +265,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
        }
 
        if (sysreq_params_size) {
+               LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " size %" PRIu32,
+                       cmd, cmd_param, param1, sysreq_params_size);
                /* Allocate memory for sysreq_params */
                retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem);
                if (retval != ERROR_OK) {
@@ -247,21 +279,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
                }
 
                /* Write sysreq_params */
-               sysreq_params[0] = param1;
+               target_buffer_set_u32(target, (uint8_t *)sysreq_params, param1);
                retval = target_write_buffer(target, sysreq_mem->address,
                                sysreq_params_size, (uint8_t *)sysreq_params);
                if (retval != ERROR_OK)
                        goto cleanup_mem;
 
                /* Set address of sysreq parameters block */
-               retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, sysreq_mem->address);
+               retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, sysreq_mem->address);
                if (retval != ERROR_OK)
                        goto cleanup_mem;
 
        } else {
                /* Sysreq without memory block of parameters */
+               LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32,
+                       cmd, cmd_param, param1);
                /* Set register parameter */
-               retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, param1);
+               retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, param1);
                if (retval != ERROR_OK)
                        goto cleanup_mem;
        }
@@ -275,26 +309,40 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
                    sysreq_wait_algorithm->address + sysreq_wait_algorithm->size);
 
        struct armv7m_common *armv7m = target_to_armv7m(target);
-       if (armv7m == NULL) {
-
+       if (!armv7m) {
                /* something is very wrong if armv7m is NULL */
                LOG_ERROR("unable to get armv7m target");
+               retval = ERROR_FAIL;
                goto cleanup;
        }
 
        /* Set SROM request */
-       retval = target_write_u32(target, PSOC4_CPUSS_SYSREQ,
+       retval = target_write_u32(target, psoc4_info->cpuss_sysreq_addr,
                                  PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd);
        if (retval != ERROR_OK)
                goto cleanup;
 
        /* Execute wait code */
        retval = target_run_algorithm(target, 0, NULL,
-                               sizeof(reg_params) / sizeof(*reg_params), reg_params,
+                               ARRAY_SIZE(reg_params), reg_params,
                                sysreq_wait_algorithm->address, 0, 1000, &armv7m_info);
-       if (retval != ERROR_OK)
+       if (retval != ERROR_OK) {
                LOG_ERROR("sysreq wait code execution failed");
+               goto cleanup;
+       }
 
+       uint32_t sysarg_out_tmp;
+       retval = target_read_u32(target, psoc4_info->cpuss_sysarg_addr, &sysarg_out_tmp);
+       if (retval != ERROR_OK)
+               goto cleanup;
+
+       if (sysarg_out) {
+               *sysarg_out = sysarg_out_tmp;
+               /* If result is an error, do not show now, let caller to decide */
+       } else if ((sysarg_out_tmp & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) {
+               LOG_ERROR("sysreq error 0x%" PRIx32, sysarg_out_tmp);
+               retval = ERROR_FAIL;
+       }
 cleanup:
        destroy_reg_param(&reg_params[0]);
 
@@ -310,103 +358,165 @@ cleanup_algo:
 
 
 /* helper routine to get silicon ID from a PSoC 4 chip */
-static int psoc4_get_silicon_id(struct target *target, uint32_t *silicon_id, uint8_t *protection)
+static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, uint16_t *family_id, uint8_t *protection)
 {
-       uint32_t params = PSOC4_SROM_KEY1
-                        | ((PSOC4_SROM_KEY2 + PSOC4_CMD_GET_SILICON_ID) << 8);
-       uint32_t part0, part1;
+       struct target *target = bank->target;
+       struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
 
-       int retval = psoc4_sysreq(target, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0);
-       if (retval != ERROR_OK)
-               return retval;
+       uint32_t part0, part1;
 
-       retval = target_read_u32(target, PSOC4_CPUSS_SYSARG, &part0);
+       int retval = psoc4_sysreq(bank, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0, &part0);
        if (retval != ERROR_OK)
                return retval;
 
-       if (part0 == params) {
-               LOG_ERROR("sysreq silicon id request not served");
+       if ((part0 & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) {
+               LOG_ERROR("sysreq error 0x%" PRIx32, part0);
                return ERROR_FAIL;
        }
 
-       retval = target_read_u32(target, PSOC4_CPUSS_SYSREQ, &part1);
+       retval = target_read_u32(target, psoc4_info->cpuss_sysreq_addr, &part1);
        if (retval != ERROR_OK)
                return retval;
 
-       uint32_t silicon = ((part0 & 0xffff) << 16)
-                       | (((part0 >> 16) & 0xff) << 8)
-                       | (part1 & 0xff);
-       uint8_t prot = (part1 >> 12) & 0xff;
-
+       /* build ID as Cypress sw does:
+        * bit 31..16 silicon ID
+        * bit 15..8  revision ID (so far 0x11 for all devices)
+        * bit 7..0   family ID (lowest 8 bits)
+        */
        if (silicon_id)
-                       *silicon_id = silicon;
+                       *silicon_id = ((part0 & 0x0000ffff) << 16)
+                                   | ((part0 & 0x00ff0000) >> 8)
+                                   | (part1 & 0x000000ff);
+
+       if (family_id)
+                       *family_id = part1 & 0x0fff;
+
        if (protection)
-                       *protection = prot;
+                       *protection = (part1 >> 12) & 0x0f;
 
-       LOG_DEBUG("silicon id: 0x%08" PRIx32 "", silicon);
-       LOG_DEBUG("protection: 0x%02" PRIx8 "", prot);
-       return retval;
+       return ERROR_OK;
 }
 
 
-static int psoc4_protect_check(struct flash_bank *bank)
+static int psoc4_get_family(struct target *target, uint16_t *family_id)
+{
+       int retval, i;
+       uint32_t pidbf[3];
+       uint8_t pid[3];
+
+       retval = target_read_memory(target, PSOC4_ROMTABLE_PID0, 4, 3, (uint8_t *)pidbf);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (i = 0; i < 3; i++) {
+               uint32_t tmp = target_buffer_get_u32(target, (uint8_t *)(pidbf + i));
+               if (tmp & 0xffffff00) {
+                       LOG_ERROR("Unexpected data in ROMTABLE");
+                       return ERROR_FAIL;
+               }
+               pid[i] = tmp & 0xff;
+       }
+
+       uint16_t family = pid[0] | ((pid[1] & 0xf) << 8);
+       uint32_t designer = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0xf) << 4);
+
+       if (designer != PSOC4_ROMTABLE_DESIGNER_CHECK) {
+               LOG_ERROR("ROMTABLE designer is not Cypress");
+               return ERROR_FAIL;
+       }
+
+       *family_id = family;
+       return ERROR_OK;
+}
+
+
+static int psoc4_flash_prepare(struct flash_bank *bank)
 {
        struct target *target = bank->target;
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
 
-       uint32_t prot_addr = PSOC4_SFLASH_MACRO;
-       uint32_t protection;
-       int i, s;
-       int num_bits;
-       int retval = ERROR_OK;
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
 
-       num_bits = bank->num_sectors;
+       uint16_t family_id;
+       int retval;
 
-       for (i = 0; i < num_bits; i += 32) {
-               retval = target_read_u32(target, prot_addr, &protection);
+       /* get family ID from SROM call */
+       retval = psoc4_get_silicon_id(bank, NULL, &family_id, NULL);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* and check with family ID from ROMTABLE */
+       if (family_id != psoc4_info->family_id) {
+               LOG_ERROR("Family mismatch");
+               return ERROR_FAIL;
+       }
+
+       if (!psoc4_info->legacy_family) {
+               uint32_t sysreq_status;
+               retval = psoc4_sysreq(bank, PSOC4_CMD_SET_IMO48, 0, NULL, 0, &sysreq_status);
                if (retval != ERROR_OK)
                        return retval;
 
-               prot_addr += 4;
-
-               for (s = 0; s < 32; s++) {
-                       if (i + s >= num_bits)
-                               break;
-                       bank->sectors[i + s].is_protected = (protection & (1 << s)) ? 1 : 0;
+               if ((sysreq_status & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) {
+                       /* This undocumented error code is returned probably when
+                        * PSOC4_CMD_SET_IMO48 command is not implemented.
+                        * Can be safely ignored, programming works.
+                        */
+                       if (sysreq_status == PSOC4_SROM_ERR_IMO_NOT_IMPLEM)
+                               LOG_INFO("PSOC4_CMD_SET_IMO48 is not implemented on this device.");
+                       else {
+                               LOG_ERROR("sysreq error 0x%" PRIx32, sysreq_status);
+                               return ERROR_FAIL;
+                       }
                }
        }
 
-       retval = psoc4_get_silicon_id(target, NULL, &(psoc4_info->chip_protection));
-       return retval;
+       return ERROR_OK;
 }
 
 
-static int psoc4_mass_erase(struct flash_bank *bank)
+static int psoc4_protect_check(struct flash_bank *bank)
 {
        struct target *target = bank->target;
-       int i;
+       struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
 
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
+       uint32_t prot_addr = PSOC4_SFLASH_MACRO0;
+       int retval;
+       uint8_t bf[PSOC4_ROWS_PER_MACRO/8];
+       unsigned int s = 0;
+
+       for (unsigned int m = 0; m < psoc4_info->num_macros; m++, prot_addr += PSOC4_SFLASH_MACRO_SIZE) {
+               retval = target_read_memory(target, prot_addr, 4, PSOC4_ROWS_PER_MACRO/32, bf);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               for (unsigned int i = 0; i < PSOC4_ROWS_PER_MACRO && s < bank->num_sectors; i++, s++)
+                       bank->sectors[s].is_protected = bf[i/8] & (1 << (i%8)) ? 1 : 0;
        }
 
-       /* Call "Erase All" system ROM API */
-       uint32_t param;
-       int retval = psoc4_sysreq(target, PSOC4_CMD_ERASE_ALL,
-                       0,
-                       &param, sizeof(param));
+       return ERROR_OK;
+}
 
-       if (retval == ERROR_OK)
-               /* set all sectors as erased */
-               for (i = 0; i < bank->num_sectors; i++)
-                       bank->sectors[i].is_erased = 1;
 
-       return retval;
+static int psoc4_mass_erase(struct flash_bank *bank)
+{
+       int retval = psoc4_flash_prepare(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Call "Erase All" system ROM API */
+       uint32_t param = 0;
+       return psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL,
+                       0,
+                       &param, sizeof(param), NULL);
 }
 
 
-static int psoc4_erase(struct flash_bank *bank, int first, int last)
+static int psoc4_erase(struct flash_bank *bank, unsigned int first,
+               unsigned int last)
 {
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
        if (psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW) {
@@ -417,67 +527,74 @@ static int psoc4_erase(struct flash_bank *bank, int first, int last)
        if ((first == 0) && (last == (bank->num_sectors - 1)))
                return psoc4_mass_erase(bank);
 
-       LOG_ERROR("Only mass erase available");
+       LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'");
 
        return ERROR_FAIL;
 }
 
 
-static int psoc4_protect(struct flash_bank *bank, int set, int first, int last)
+static int psoc4_protect(struct flash_bank *bank, int set, unsigned int first,
+               unsigned int last)
 {
        struct target *target = bank->target;
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
 
-       if (psoc4_info->probed == 0)
+       if (!psoc4_info->probed)
                return ERROR_FAIL;
 
-       if (target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       int retval = psoc4_flash_prepare(bank);
+       if (retval != ERROR_OK)
+               return retval;
 
        uint32_t *sysrq_buffer = NULL;
-       int retval;
-       int num_bits = bank->num_sectors;
        const int param_sz = 8;
-       int prot_sz = num_bits / 8;
        int chip_prot = PSOC4_CHIP_PROT_OPEN;
-       int flash_macro = 0; /* PSoC 42xx has only macro 0 */
-       int i;
+       unsigned int i;
+       unsigned int num_bits = bank->num_sectors;
 
-       sysrq_buffer = calloc(1, param_sz + prot_sz);
-       if (sysrq_buffer == NULL) {
+       if (num_bits > PSOC4_ROWS_PER_MACRO)
+               num_bits = PSOC4_ROWS_PER_MACRO;
+
+       int prot_sz = num_bits / 8;
+
+       sysrq_buffer = malloc(param_sz + prot_sz);
+       if (!sysrq_buffer) {
                LOG_ERROR("no memory for row buffer");
                return ERROR_FAIL;
        }
 
-       for (i = first; i < num_bits && i <= last; i++)
+       for (i = first; i <= last && i < bank->num_sectors; i++)
                bank->sectors[i].is_protected = set;
 
-       uint32_t *p = sysrq_buffer + 2;
-       for (i = 0; i < num_bits; i++) {
-               if (bank->sectors[i].is_protected)
-                       p[i / 32] |= 1 << (i % 32);
-       }
+       for (unsigned int m = 0, sect = 0; m < psoc4_info->num_macros; m++) {
+               uint8_t *p = (uint8_t *)(sysrq_buffer + 2);
+               memset(p, 0, prot_sz);
+               for (i = 0; i < num_bits && sect < bank->num_sectors; i++, sect++) {
+                       if (bank->sectors[sect].is_protected)
+                               p[i/8] |= 1 << (i%8);
+               }
 
-       /* Call "Load Latch" system ROM API */
-       sysrq_buffer[1] = prot_sz - 1;
-       retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
-                       0,      /* Byte number in latch from what to write */
-                       sysrq_buffer, param_sz + psoc4_info->row_size);
-       if (retval != ERROR_OK)
-               goto cleanup;
+               /* Call "Load Latch" system ROM API */
+               target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1),
+                                       prot_sz - 1);
+               retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH,
+                       0       /* Byte number in latch from what to write */
+                         | (m << 8), /* flash macro index */
+                       sysrq_buffer, param_sz + prot_sz,
+                       NULL);
+               if (retval != ERROR_OK)
+                       break;
 
-       /* Call "Write Protection" system ROM API */
-       retval = psoc4_sysreq(target, PSOC4_CMD_WRITE_PROTECTION,
-                       chip_prot | (flash_macro << 8), NULL, 0);
-cleanup:
-       if (retval != ERROR_OK)
-               psoc4_protect_check(bank);
+               /* Call "Write Protection" system ROM API */
+               retval = psoc4_sysreq(bank, PSOC4_CMD_WRITE_PROTECTION,
+                       chip_prot | (m << 8), NULL, 0, NULL);
+               if (retval != ERROR_OK)
+                       break;
+       }
 
-       if (sysrq_buffer)
-               free(sysrq_buffer);
+       free(sysrq_buffer);
 
+       psoc4_protect_check(bank);
        return retval;
 }
 
@@ -489,7 +606,7 @@ COMMAND_HANDLER(psoc4_handle_flash_autoerase_command)
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
+       if (retval != ERROR_OK)
                return retval;
 
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
@@ -513,24 +630,17 @@ COMMAND_HANDLER(psoc4_handle_flash_autoerase_command)
 static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
-       struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
        struct target *target = bank->target;
+       struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
        uint32_t *sysrq_buffer = NULL;
-       int retval = ERROR_OK;
        const int param_sz = 8;
 
-       if (bank->target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       if (offset & 0x1) {
-               LOG_ERROR("offset 0x%08" PRIx32 " breaks required 2-byte alignment", offset);
-               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
-       }
+       int retval = psoc4_flash_prepare(bank);
+       if (retval != ERROR_OK)
+               return retval;
 
        sysrq_buffer = malloc(param_sz + psoc4_info->row_size);
-       if (sysrq_buffer == NULL) {
+       if (!sysrq_buffer) {
                LOG_ERROR("no memory for row buffer");
                return ERROR_FAIL;
        }
@@ -539,34 +649,40 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
        uint32_t row_num = offset / psoc4_info->row_size;
        uint32_t row_offset = offset - row_num * psoc4_info->row_size;
        if (row_offset)
-               memset(row_buffer, 0, row_offset);
+               memset(row_buffer, bank->default_padded_value, row_offset);
 
-       bool save_poll = jtag_poll_get_enabled();
-       jtag_poll_set_enabled(false);
+       /* Mask automatic polling triggered by execution of halted events */
+       bool save_poll_mask = jtag_poll_mask();
 
        while (count) {
                uint32_t chunk_size = psoc4_info->row_size - row_offset;
                if (chunk_size > count) {
                        chunk_size = count;
-                       memset(row_buffer + chunk_size, 0, psoc4_info->row_size - chunk_size);
+                       memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size);
                }
                memcpy(row_buffer + row_offset, buffer, chunk_size);
                LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "",
                                offset, row_offset, chunk_size);
 
+               uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO;
+
                /* Call "Load Latch" system ROM API */
-               sysrq_buffer[1] = psoc4_info->row_size - 1;
-               retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
-                               0,      /* Byte number in latch from what to write */
-                               sysrq_buffer, param_sz + psoc4_info->row_size);
+               target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1),
+                                       psoc4_info->row_size - 1);
+               retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH,
+                               0       /* Byte number in latch from what to write */
+                                 | (macro_idx << 8),
+                               sysrq_buffer, param_sz + psoc4_info->row_size,
+                               NULL);
                if (retval != ERROR_OK)
                        goto cleanup;
 
                /* Call "Program Row" or "Write Row" system ROM API */
                uint32_t sysrq_param;
-               retval = psoc4_sysreq(target, psoc4_info->cmd_program_row,
+               retval = psoc4_sysreq(bank, psoc4_info->cmd_program_row,
                                row_num & 0xffff,
-                               &sysrq_param, sizeof(sysrq_param));
+                               &sysrq_param, sizeof(sysrq_param),
+                               NULL);
                if (retval != ERROR_OK)
                        goto cleanup;
 
@@ -577,93 +693,89 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
        }
 
 cleanup:
-       jtag_poll_set_enabled(save_poll);
-
-       if (sysrq_buffer)
-               free(sysrq_buffer);
+       jtag_poll_unmask(save_poll_mask);
 
+       free(sysrq_buffer);
        return retval;
 }
 
 
+/* Due to Cypress's method of market segmentation some devices
+ * have accessible only 1/2, 1/4 or 1/8 of SPCIF described flash */
+static int psoc4_test_flash_wounding(struct target *target, uint32_t flash_size)
+{
+       int retval, i;
+       for (i = 3; i >= 1; i--) {
+               uint32_t addr = flash_size >> i;
+               uint32_t dummy;
+               retval = target_read_u32(target, addr, &dummy);
+               if (retval != ERROR_OK)
+                       return i;
+       }
+       return 0;
+}
+
+
 static int psoc4_probe(struct flash_bank *bank)
 {
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
        struct target *target = bank->target;
-       uint32_t flash_size_in_kb = 0;
-       uint32_t max_flash_size_in_kb;
-       uint32_t cpu_id;
-       uint32_t silicon_id;
-       uint32_t row_size;
-       uint32_t base_address = 0x00000000;
-       uint8_t protection;
 
-       if (target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
+       int retval;
+       uint16_t family_id;
 
-       psoc4_info->probed = 0;
-       psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW;
+       psoc4_info->probed = false;
 
-       /* Get the CPUID from the ARM Core
-        * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */
-       int retval = target_read_u32(target, 0xE000ED00, &cpu_id);
+       retval = psoc4_get_family(target, &family_id);
        if (retval != ERROR_OK)
                return retval;
 
-       LOG_DEBUG("cpu id = 0x%08" PRIx32 "", cpu_id);
+       const struct psoc4_chip_family *family = psoc4_family_by_id(family_id);
 
-       /* set page size, protection granularity and max flash size depending on family */
-       switch ((cpu_id >> 4) & 0xFFF) {
-       case 0xc20: /* M0 -> PSoC4 */
-               row_size = 128;
-               max_flash_size_in_kb = 32;
-               break;
-       default:
-               LOG_WARNING("Cannot identify target as a PSoC 4 family.");
+       if (family->id == 0) {
+               LOG_ERROR("Cannot identify PSoC 4 family.");
                return ERROR_FAIL;
        }
 
-       uint32_t spcif_geometry;
-       retval = target_read_u32(target, PSOC4_SPCIF_GEOMETRY, &spcif_geometry);
-       if (retval == ERROR_OK) {
-               row_size = 128 * ((spcif_geometry >> 22) & 3);
-               flash_size_in_kb = (spcif_geometry & 0xffff) * 256 / 1024;
-               LOG_INFO("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.",
-                        flash_size_in_kb, row_size);
+       if (family->flags & PSOC4_FAMILY_FLAG_LEGACY) {
+               LOG_INFO("%s legacy family detected.", family->name);
+               psoc4_info->legacy_family = true;
+               psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_LEGACY;
+               psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_LEGACY;
+               psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_LEGACY;
+       } else {
+               LOG_INFO("%s family detected.", family->name);
+               psoc4_info->legacy_family = false;
+               psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_NEW;
+               psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_NEW;
+               psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_NEW;
        }
 
-       /* Early revisions of ST-Link v2 have some problem reading PSOC4_SPCIF_GEOMETRY
-               and an error is reported late. Dummy read gets this error. */
-       uint32_t dummy;
-       target_read_u32(target, PSOC4_CPUSS_SYSREQ, &dummy);
-
-       /* get silicon ID from target. */
-       retval = psoc4_get_silicon_id(target, &silicon_id, &protection);
+       uint32_t spcif_geometry;
+       retval = target_read_u32(target, psoc4_info->spcif_geometry_addr, &spcif_geometry);
        if (retval != ERROR_OK)
                return retval;
 
-       const struct psoc4_chip_details *details = psoc4_details_by_id(silicon_id);
-       if (details) {
-               LOG_INFO("%s device detected.", details->type);
-               if (flash_size_in_kb == 0)
-                       flash_size_in_kb = details->flash_size_in_kb;
-               else if (flash_size_in_kb != details->flash_size_in_kb)
-                       LOG_ERROR("Flash size mismatch");
+       uint32_t flash_size_in_kb = spcif_geometry & 0x3fff;
+       /* TRM of legacy, M and L version describes FLASH field as 16-bit.
+        * S-series and PSoC Analog Coprocessor changes spec to 14-bit only.
+        * Impose PSoC Analog Coprocessor limit to all devices as it
+        * does not make any harm: flash size is safely below 4 MByte limit
+        */
+       uint32_t row_size = (spcif_geometry >> 22) & 3;
+       uint32_t num_macros = (spcif_geometry >> 20) & 3;
+
+       if (psoc4_info->legacy_family) {
+               flash_size_in_kb = flash_size_in_kb * 256 / 1024;
+               row_size *= 128;
+       } else {
+               flash_size_in_kb = (flash_size_in_kb + 1) * 256 / 1024;
+               row_size = 64 * (row_size + 1);
+               num_macros++;
        }
 
-       psoc4_info->row_size = row_size;
-       psoc4_info->silicon_id = silicon_id;
-       psoc4_info->chip_protection = protection;
-
-       /* failed reading flash size or flash size invalid (early silicon),
-        * default to max target family */
-       if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
-               LOG_WARNING("PSoC 4 flash size failed, probe inaccurate - assuming %" PRIu32 " k flash",
-                       max_flash_size_in_kb);
-               flash_size_in_kb = max_flash_size_in_kb;
-       }
+       LOG_DEBUG("SPCIF geometry: %" PRIu32 " KiB flash, row %" PRIu32 " bytes.",
+                flash_size_in_kb, row_size);
 
        /* if the user sets the size manually then ignore the probed value
         * this allows us to work around devices that have a invalid flash size register value */
@@ -672,37 +784,42 @@ static int psoc4_probe(struct flash_bank *bank)
                flash_size_in_kb = psoc4_info->user_bank_size / 1024;
        }
 
-       LOG_INFO("flash size = %" PRIu32 " kbytes", flash_size_in_kb);
+       char macros_txt[20] = "";
+       if (num_macros > 1)
+               snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros);
 
-       /* did we assign flash size? */
-       assert(flash_size_in_kb != 0xffff);
+       LOG_INFO("flash size = %" PRIu32 " KiB%s", flash_size_in_kb, macros_txt);
 
-       /* calculate numbers of pages */
+       /* calculate number of pages */
        uint32_t num_rows = flash_size_in_kb * 1024 / row_size;
 
-       /* check that calculation result makes sense */
-       assert(num_rows > 0);
+       /* check number of flash macros */
+       if (num_macros != (num_rows + PSOC4_ROWS_PER_MACRO - 1) / PSOC4_ROWS_PER_MACRO)
+               LOG_WARNING("Number of macros does not correspond with flash size!");
 
-       if (bank->sectors) {
-               free(bank->sectors);
-               bank->sectors = NULL;
+       if (!psoc4_info->legacy_family) {
+               int wounding = psoc4_test_flash_wounding(target, num_rows * row_size);
+               if (wounding > 0) {
+                       flash_size_in_kb = flash_size_in_kb >> wounding;
+                       num_rows = num_rows >> wounding;
+                       LOG_INFO("WOUNDING detected: accessible flash size %" PRIu32 " kbytes", flash_size_in_kb);
+               }
        }
 
-       bank->base = base_address;
+       free(bank->sectors);
+
+       psoc4_info->family_id = family_id;
+       psoc4_info->num_macros = num_macros;
+       psoc4_info->row_size = row_size;
+       bank->base = 0x00000000;
        bank->size = num_rows * row_size;
        bank->num_sectors = num_rows;
-       bank->sectors = malloc(sizeof(struct flash_sector) * num_rows);
-
-       uint32_t i;
-       for (i = 0; i < num_rows; i++) {
-               bank->sectors[i].offset = i * row_size;
-               bank->sectors[i].size = row_size;
-               bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 1;
-       }
+       bank->sectors = alloc_block_array(0, row_size, num_rows);
+       if (!bank->sectors)
+               return ERROR_FAIL;
 
-       LOG_INFO("flash bank set %" PRIu32 " rows", num_rows);
-       psoc4_info->probed = 1;
+       LOG_DEBUG("flash bank set %" PRIu32 " rows", num_rows);
+       psoc4_info->probed = true;
 
        return ERROR_OK;
 }
@@ -716,30 +833,42 @@ static int psoc4_auto_probe(struct flash_bank *bank)
 }
 
 
-static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size)
+static int get_psoc4_info(struct flash_bank *bank, struct command_invocation *cmd)
 {
+       struct target *target = bank->target;
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
-       int printed = 0;
 
-       if (psoc4_info->probed == 0)
+       if (!psoc4_info->probed)
                return ERROR_FAIL;
 
-       const struct psoc4_chip_details *details = psoc4_details_by_id(psoc4_info->silicon_id);
+       const struct psoc4_chip_family *family = psoc4_family_by_id(psoc4_info->family_id);
+       uint32_t size_in_kb = bank->size / 1024;
+
+       if (target->state != TARGET_HALTED) {
+               command_print_sameline(cmd, "%s, flash %" PRIu32 " kb"
+                       " (halt target to see details)", family->name, size_in_kb);
+               return ERROR_OK;
+       }
 
-       if (details) {
-               uint32_t chip_revision = psoc4_info->silicon_id & 0xffff;
-               printed = snprintf(buf, buf_size, "PSoC 4 %s rev 0x%04" PRIx32 " package %s",
-                               details->type, chip_revision, details->package);
-       } else
-               printed = snprintf(buf, buf_size, "PSoC 4 silicon id 0x%08" PRIx32 "",
-                               psoc4_info->silicon_id);
+       uint32_t silicon_id;
+       uint16_t family_id;
+       uint8_t protection;
 
-       buf += printed;
-       buf_size -= printed;
+       int retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection);
+       if (retval != ERROR_OK)
+               return retval;
 
-       const char *prot_txt = psoc4_decode_chip_protection(psoc4_info->chip_protection);
-       uint32_t size_in_kb = bank->size / 1024;
-       snprintf(buf, buf_size, " flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
+       if (family_id != psoc4_info->family_id)
+               command_print_sameline(cmd, "Family id mismatch 0x%02" PRIx16
+                       "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32,
+                       psoc4_info->family_id, family_id, silicon_id);
+       else {
+               command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32 "",
+                       family->name, silicon_id);
+       }
+
+       const char *prot_txt = psoc4_decode_chip_protection(protection);
+       command_print_sameline(cmd, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
        return ERROR_OK;
 }
 
@@ -751,14 +880,14 @@ COMMAND_HANDLER(psoc4_handle_mass_erase_command)
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
+       if (retval != ERROR_OK)
                return retval;
 
        retval = psoc4_mass_erase(bank);
        if (retval == ERROR_OK)
-               command_print(CMD_CTX, "psoc mass erase complete");
+               command_print(CMD, "psoc mass erase complete");
        else
-               command_print(CMD_CTX, "psoc mass erase failed");
+               command_print(CMD, "psoc mass erase failed");
 
        return retval;
 }
@@ -793,7 +922,7 @@ static const struct command_registration psoc4_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
-struct flash_driver psoc4_flash = {
+const struct flash_driver psoc4_flash = {
        .name = "psoc4",
        .commands = psoc4_command_handlers,
        .flash_bank_command = psoc4_flash_bank_command,
@@ -806,4 +935,5 @@ struct flash_driver psoc4_flash = {
        .erase_check = default_flash_blank_check,
        .protect_check = psoc4_protect_check,
        .info = get_psoc4_info,
+       .free_driver_priv = default_flash_free_driver_priv,
 };