flash/nor/psoc4: fix warnings
[openocd.git] / src / flash / nor / psoc4.c
index c7c85737cbbe4d6054ee62734668715633c82001..62b904ed12663673e9614bc286f8798729897362 100644 (file)
        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                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_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 },
-       { 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;
-       int probed;
-       uint32_t silicon_id;
-       uint8_t chip_protection;
+       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)
@@ -176,7 +207,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;
 }
@@ -189,9 +222,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;
 
@@ -212,8 +250,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
@@ -238,6 +276,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) {
@@ -250,21 +290,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;
        }
@@ -279,14 +321,14 @@ 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) {
-
                /* 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;
@@ -295,9 +337,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);
-       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]);
 
@@ -313,92 +369,162 @@ 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 (lowes 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;
+
+       /* get family ID from SROM call */
+       retval = psoc4_get_silicon_id(bank, NULL, &family_id, NULL);
+       if (retval != ERROR_OK)
+               return retval;
 
-       for (i = 0; i < num_bits; i += 32) {
-               retval = target_read_u32(target, prot_addr, &protection);
+       /* 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;
+       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 */
-       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,
-                       &param, sizeof(param));
+                       &param, sizeof(param), NULL);
 
        if (retval == ERROR_OK)
                /* set all sectors as erased */
@@ -420,7 +546,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);
 
-       LOG_ERROR("Only mass erase available");
+       LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'");
 
        return ERROR_FAIL;
 }
@@ -431,22 +557,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;
 
-       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;
+       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) {
@@ -454,33 +581,38 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last)
                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 (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);
 
+       psoc4_protect_check(bank);
        return retval;
 }
 
@@ -516,21 +648,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)
 {
-       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) {
@@ -542,7 +667,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)
-               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);
@@ -551,25 +676,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;
-                       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;
 
@@ -589,84 +720,82 @@ cleanup:
 }
 
 
+/* 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 " 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 */
@@ -675,37 +804,44 @@ 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 " 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;
 
-       /* 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 (!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);
+               }
+       }
 
        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->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;
 }
@@ -721,28 +857,45 @@ static int psoc4_auto_probe(struct flash_bank *bank)
 
 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;
-       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) {
+               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;
 
-       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);
+       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;
 
-       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;
 }
 

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)