psoc4: update for 4x00BLE, L, M, S and PRoC BLE devices 07/3807/7
authorTomas Vanek <vanekt@fbl.cz>
Fri, 26 Aug 2016 19:03:27 +0000 (21:03 +0200)
committerTomas Vanek <vanekt@fbl.cz>
Wed, 14 Feb 2018 08:26:40 +0000 (08:26 +0000)
Flash ROM API command PSOC4_CMD_SET_IMO48 is now optional on new devices.
Also code tidy up:
- improved system ROM call error detection
- probe does not require the target to be halted
- default_padded_value and erased_value set to 0
- fixed endianess problem in flash write and protection setting
- removed fancy chip detection table as it would be updated too often
- psoc4 flash_autoerase is now on by default to ease programming

psoc4.cfg distinguishes chip family and uses either proprietary acquire
function of a KitProg adapter or TEST_MODE workaround to "reset halt"

Change-Id: I2c75ec46ed0a95e09274fad70b62d6eed7b9ecdf
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3807
Tested-by: jenkins
Reviewed-by: David Girault <david.f.girault@gmail.com>
src/flash/nor/psoc4.c
tcl/target/psoc4.cfg

index c7c85737cbbe4d6054ee62734668715633c82001..1d861edc9d538cb41cab754b3b646bbb31678fbf 100644 (file)
        Document Number: 001-87197 Rev. *B  Revised August 29, 2013
 
  PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM
        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(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
  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
 */
 
 /* register locations */
 */
 
 /* 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 */
 
 /* constants */
+#define PSOC4_SFLASH_MACRO_SIZE                0x400
+#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_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_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_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_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_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
 
 
-struct psoc4_chip_details {
+#define PSOC4_FAMILY_FLAG_LEGACY       1
+
+struct psoc4_chip_family {
        uint16_t id;
        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 },
-       { 0x041C, "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 },
-       { 0x0416, "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 },
+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;
 };
 
 
 struct psoc4_flash_bank {
        uint32_t row_size;
        uint32_t user_bank_size;
-       int probed;
-       uint32_t silicon_id;
-       uint8_t chip_protection;
+       int num_macros;
+       bool probed;
        uint8_t cmd_program_row;
        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)
 }
 
 static const char *psoc4_decode_chip_protection(uint8_t protection)
@@ -176,7 +205,9 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
        psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank));
 
        bank->driver_priv = psoc4_info;
        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->user_bank_size = bank->size;
+       psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW;
 
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
@@ -189,9 +220,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
  */
  *  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;
 
        struct working_area *sysreq_wait_algorithm;
        struct working_area *sysreq_mem;
 
@@ -212,8 +248,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 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
                ERASE_ALL       144
                PROGRAM_ROW     112
                other sysreq     68
@@ -238,6 +274,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
        }
 
        if (sysreq_params_size) {
        }
 
        if (sysreq_params_size) {
+               LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " %08" PRIx32 " size %" PRIu32,
+                       cmd, cmd_param, param1, sysreq_params[0], sysreq_params_size);
                /* Allocate memory for sysreq_params */
                retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem);
                if (retval != ERROR_OK) {
                /* Allocate memory for sysreq_params */
                retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem);
                if (retval != ERROR_OK) {
@@ -250,21 +288,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
                }
 
                /* Write sysreq_params */
                }
 
                /* 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_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 */
                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 */
                /* 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;
        }
                if (retval != ERROR_OK)
                        goto cleanup_mem;
        }
@@ -279,14 +319,13 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
 
        struct armv7m_common *armv7m = target_to_armv7m(target);
        if (armv7m == NULL) {
 
        struct armv7m_common *armv7m = target_to_armv7m(target);
        if (armv7m == NULL) {
-
                /* something is very wrong if armv7m is NULL */
                LOG_ERROR("unable to get armv7m target");
                goto cleanup;
        }
 
        /* Set SROM request */
                /* something is very wrong if armv7m is NULL */
                LOG_ERROR("unable to get armv7m target");
                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;
                                  PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd);
        if (retval != ERROR_OK)
                goto cleanup;
@@ -295,9 +334,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
        retval = target_run_algorithm(target, 0, NULL,
                                sizeof(reg_params) / sizeof(*reg_params), reg_params,
                                sysreq_wait_algorithm->address, 0, 1000, &armv7m_info);
        retval = target_run_algorithm(target, 0, NULL,
                                sizeof(reg_params) / sizeof(*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");
                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]);
 
 cleanup:
        destroy_reg_param(&reg_params[0]);
 
@@ -313,92 +366,162 @@ cleanup_algo:
 
 
 /* helper routine to get silicon ID from a PSoC 4 chip */
 
 
 /* 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 (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;
        }
 
                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;
 
        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 (lowes 8 bits)
+        */
        if (silicon_id)
        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)
        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;
 
 {
        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;
 
                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;
 {
        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;
+       int s = 0;
+       int m, i;
+       uint8_t bf[PSOC4_ROWS_PER_MACRO/8];
+
+       for (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 (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;
        }
 
        }
 
+       return ERROR_OK;
+}
+
+
+static int psoc4_mass_erase(struct flash_bank *bank)
+{
+       int i;
+       int retval = psoc4_flash_prepare(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
        /* Call "Erase All" system ROM API */
        /* Call "Erase All" system ROM API */
-       uint32_t param;
-       int retval = psoc4_sysreq(target, PSOC4_CMD_ERASE_ALL,
+       uint32_t param = 0;
+       retval = psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL,
                        0,
                        0,
-                       &param, sizeof(param));
+                       &param, sizeof(param), NULL);
 
        if (retval == ERROR_OK)
                /* set all sectors as erased */
 
        if (retval == ERROR_OK)
                /* set all sectors as erased */
@@ -420,7 +543,7 @@ 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);
 
        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;
 }
 
        return ERROR_FAIL;
 }
@@ -431,22 +554,23 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last)
        struct target *target = bank->target;
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
 
        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;
 
                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;
 
        uint32_t *sysrq_buffer = NULL;
-       int retval;
-       int num_bits = bank->num_sectors;
        const int param_sz = 8;
        const int param_sz = 8;
-       int prot_sz = num_bits / 8;
        int chip_prot = PSOC4_CHIP_PROT_OPEN;
        int chip_prot = PSOC4_CHIP_PROT_OPEN;
-       int flash_macro = 0; /* PSoC 42xx has only macro 0 */
-       int i;
+       int i, m;
+       int num_bits = bank->num_sectors;
+
+       if (num_bits > PSOC4_ROWS_PER_MACRO)
+               num_bits = PSOC4_ROWS_PER_MACRO;
+
+       int prot_sz = num_bits / 8;
 
        sysrq_buffer = calloc(1, param_sz + prot_sz);
        if (sysrq_buffer == NULL) {
 
        sysrq_buffer = calloc(1, param_sz + prot_sz);
        if (sysrq_buffer == NULL) {
@@ -454,33 +578,38 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last)
                return ERROR_FAIL;
        }
 
                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;
 
                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 (m = 0; m < psoc4_info->num_macros; m++) {
+               uint8_t *p = (uint8_t *)(sysrq_buffer + 2);
+               for (i = 0; i < num_bits && i < bank->num_sectors; i++) {
+                       if (bank->sectors[i].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 + psoc4_info->row_size,
+                       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);
 
 
        if (sysrq_buffer)
                free(sysrq_buffer);
 
+       psoc4_protect_check(bank);
        return retval;
 }
 
        return retval;
 }
 
@@ -516,21 +645,14 @@ 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)
 {
 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 target *target = bank->target;
+       struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
        uint32_t *sysrq_buffer = NULL;
        uint32_t *sysrq_buffer = NULL;
-       int retval = ERROR_OK;
        const int param_sz = 8;
 
        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) {
 
        sysrq_buffer = malloc(param_sz + psoc4_info->row_size);
        if (sysrq_buffer == NULL) {
@@ -542,7 +664,7 @@ 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)
        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);
 
        bool save_poll = jtag_poll_get_enabled();
        jtag_poll_set_enabled(false);
@@ -551,25 +673,31 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t chunk_size = psoc4_info->row_size - row_offset;
                if (chunk_size > count) {
                        chunk_size = 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);
 
                }
                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 */
                /* 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;
                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,
                                row_num & 0xffff,
-                               &sysrq_param, sizeof(sysrq_param));
+                               &sysrq_param, sizeof(sysrq_param),
+                               NULL);
                if (retval != ERROR_OK)
                        goto cleanup;
 
                if (retval != ERROR_OK)
                        goto cleanup;
 
@@ -593,80 +721,62 @@ static int psoc4_probe(struct flash_bank *bank)
 {
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
        struct target *target = bank->target;
 {
        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;
 
        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;
        }
 
                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;
 
        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 " kb 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 */
 
        /* 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 */
@@ -675,37 +785,35 @@ static int psoc4_probe(struct flash_bank *bank)
                flash_size_in_kb = psoc4_info->user_bank_size / 1024;
        }
 
                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 " kbytes%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;
 
        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);
 
        if (bank->sectors) {
                free(bank->sectors);
-               bank->sectors = NULL;
        }
 
        }
 
-       bank->base = base_address;
+       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->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 == NULL)
+               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;
 }
 
        return ERROR_OK;
 }
@@ -721,28 +829,45 @@ 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, char *buf, int buf_size)
 {
+       struct target *target = bank->target;
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
        struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
-       int printed = 0;
 
 
-       if (psoc4_info->probed == 0)
+       if (!psoc4_info->probed)
                return ERROR_FAIL;
 
                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 (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);
+       if (target->state != TARGET_HALTED) {
+               snprintf(buf, buf_size, "%s, flash %" PRIu32 " kb"
+                       " (halt target to see details)", family->name, size_in_kb);
+               return ERROR_OK;
+       }
+
+       int retval;
+       int printed = 0;
+       uint32_t silicon_id;
+       uint16_t family_id;
+       uint8_t protection;
+
+       retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (family_id != psoc4_info->family_id)
+               printed = snprintf(buf, buf_size, "Family id mismatch 0x%02" PRIx16
+                       "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32,
+                       psoc4_info->family_id, family_id, silicon_id);
+       else {
+               printed = snprintf(buf, buf_size, "%s silicon id 0x%08" PRIx32 "",
+                       family->name, silicon_id);
+       }
 
        buf += printed;
        buf_size -= printed;
 
 
        buf += printed;
        buf_size -= printed;
 
-       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);
+       const char *prot_txt = psoc4_decode_chip_protection(protection);
+       snprintf(buf, buf_size, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
index d443b014499e1838ba26ba9c4f535e932a3ca989..5d6dcede33b7ed09a6119d04c3ff334bbbae4654 100644 (file)
@@ -1,4 +1,4 @@
-# script for Cypress PSoC 41xx/42xx family
+# script for Cypress PSoC 4 devices
 
 #
 # PSoC 4 devices support SWD transports only.
 
 #
 # PSoC 4 devices support SWD transports only.
@@ -53,8 +53,14 @@ adapter_khz 1500
 # set in time frame 400 usec delayed about 1 msec from reset.
 #
 # OpenOCD have no standard way how to set TEST_MODE in specified time frame.
 # set in time frame 400 usec delayed about 1 msec from reset.
 #
 # OpenOCD have no standard way how to set TEST_MODE in specified time frame.
-# TEST_MODE flag is set before reset instead. It worked for tested chips
-# despite it is not guaranteed by specification.
+# As a workaround the TEST_MODE flag is set before reset instead.
+# It worked for the oldest family PSoC4100/4200 even though it is not guaranteed
+# by specification.
+#
+# Newer families like PSoC 4000, 4100M, 4200M, 4100L, 4200L and PSoC 4 BLE
+# clear TEST_MODE flag during device reset so workaround is not possible.
+# Use a KitProg adapter for theese devices or "reset halt" will not stop
+# before executing user code.
 #
 # 3) SWD cannot be connected during system initialization after reset.
 # This might be a reason for unconnecting ST-Link v2 when deasserting reset.
 #
 # 3) SWD cannot be connected during system initialization after reset.
 # This might be a reason for unconnecting ST-Link v2 when deasserting reset.
@@ -66,11 +72,34 @@ if {![using_hla]} {
    cortex_m reset_config sysresetreq
 }
 
    cortex_m reset_config sysresetreq
 }
 
+proc psoc4_get_family_id {} {
+       set err [catch "mem2array romtable_pid 32 0xF0000FE0 3"]
+       if { $err } {
+               return 0
+       }
+       if { [expr $romtable_pid(0) & 0xffffff00 ]
+         || [expr $romtable_pid(1) & 0xffffff00 ]
+         || [expr $romtable_pid(2) & 0xffffff00 ] } {
+               echo "Unexpected data in ROMTABLE"
+               return 0
+       }
+       set designer_id [expr (( $romtable_pid(1) & 0xf0 ) >> 4) | (( $romtable_pid(2) & 0xf ) << 4 ) ]
+       if { $designer_id != 0xb4 } {
+               echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id]
+               return 0
+       }
+       set family_id [expr ( $romtable_pid(0) & 0xff ) | (( $romtable_pid(1) & 0xf ) << 8 ) ]
+       return $family_id
+}
+
 proc ocd_process_reset_inner { MODE } {
 proc ocd_process_reset_inner { MODE } {
-       if { 0 != [string compare psoc4.cpu [target names]] } {
-               return -code error "PSoC 4 reset can handle only one psoc4.cpu target";
+       global PSOC4_USE_ACQUIRE PSOC4_TEST_MODE_WORKAROUND
+       global _TARGETNAME
+
+       if { 0 != [string compare $_TARGETNAME [target names]] } {
+               return -code error "PSoC 4 reset can handle only one $_TARGETNAME target";
        }
        }
-       set t psoc4.cpu
+       set t $_TARGETNAME
 
        # If this target must be halted...
        set halt -1
 
        # If this target must be halted...
        set halt -1
@@ -87,17 +116,42 @@ proc ocd_process_reset_inner { MODE } {
                return -code error "Invalid mode: $MODE, must be one of: halt, init, or run";
        }
 
                return -code error "Invalid mode: $MODE, must be one of: halt, init, or run";
        }
 
+       if { ! [info exists PSOC4_USE_ACQUIRE] } {
+               if { 0 == [string compare [adapter_name] kitprog ] } {
+                       set PSOC4_USE_ACQUIRE 1
+               } else {
+                       set PSOC4_USE_ACQUIRE 0
+               }
+       }
+       if { $PSOC4_USE_ACQUIRE } {
+               set PSOC4_TEST_MODE_WORKAROUND 0
+       } elseif { ! [info exists PSOC4_TEST_MODE_WORKAROUND] } {
+               if { [psoc4_get_family_id] == 0x93 } {
+                       set PSOC4_TEST_MODE_WORKAROUND 1
+               } else {
+                       set PSOC4_TEST_MODE_WORKAROUND 0
+               }
+       }
+
        #$t invoke-event reset-start
        $t invoke-event reset-assert-pre
 
        #$t invoke-event reset-start
        $t invoke-event reset-assert-pre
 
-       set TEST_MODE 0x40030014
-       if { $halt == 1 } {
-               mww $TEST_MODE 0x80000000
+       if { $halt && $PSOC4_USE_ACQUIRE } {
+               catch { [adapter_name] acquire_psoc }
+               $t arp_examine
        } else {
        } else {
-               mww $TEST_MODE 0
+               if { $PSOC4_TEST_MODE_WORKAROUND } {
+                       set TEST_MODE 0x40030014
+                       if { $halt == 1 } {
+                               catch { mww $TEST_MODE 0x80000000 }
+                       } else {
+                               catch { mww $TEST_MODE 0 }
+                       }
+               }
+
+               $t arp_reset assert 0
        }
 
        }
 
-       $t arp_reset assert 0
        $t invoke-event reset-assert-post
        $t invoke-event reset-deassert-pre
        if {![using_hla]} {     # workaround ST-Link v2 fails and forcing reconnect
        $t invoke-event reset-assert-post
        $t invoke-event reset-deassert-pre
        if {![using_hla]} {     # workaround ST-Link v2 fails and forcing reconnect
@@ -127,7 +181,14 @@ proc ocd_process_reset_inner { MODE } {
                set pc [ocd_reg pc]
                regsub {pc[^:]*: } $pc "" pc
                if { $pc < 0x10000000 || $pc > 0x1000ffff } {
                set pc [ocd_reg pc]
                regsub {pc[^:]*: } $pc "" pc
                if { $pc < 0x10000000 || $pc > 0x1000ffff } {
-                       return -code error [format "TARGET: %s - Not halted in system ROM, use 'reset_config none'" $t]
+                       set hint ""
+                       set family_id [psoc4_get_family_id]
+                       if { $family_id == 0x93 } {
+                               set hint ", use 'reset_config none'"
+                       } elseif { $family_id > 0x93 } {
+                               set hint ", use a KitProg adapter"
+                       }
+                       return -code error [format "TARGET: %s - Not halted in system ROM%s" $t $hint]
                }
 
                # Set registers to reset vector values
                }
 
                # Set registers to reset vector values
@@ -135,7 +196,9 @@ proc ocd_process_reset_inner { MODE } {
                reg pc [expr $value(1) & 0xfffffffe ]
                reg msp $value(0)
 
                reg pc [expr $value(1) & 0xfffffffe ]
                reg msp $value(0)
 
-               mww $TEST_MODE 0
+               if { $PSOC4_TEST_MODE_WORKAROUND } {
+                       catch { mww $TEST_MODE 0 }
+               }
        }
 
        #Pass 2 - if needed "init"
        }
 
        #Pass 2 - if needed "init"

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)