From: Tomas Vanek Date: Fri, 26 Aug 2016 19:03:27 +0000 (+0200) Subject: psoc4: update for 4x00BLE, L, M, S and PRoC BLE devices X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=38030e011542a894237b517c065d22db97525954;p=openocd psoc4: update for 4x00BLE, L, M, S and PRoC BLE devices 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 Reviewed-on: http://openocd.zylin.com/3807 Tested-by: jenkins Reviewed-by: David Girault --- diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index c7c85737..1d861edc 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -41,24 +41,65 @@ 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 */ /* 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) @@ -66,6 +107,10 @@ #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 @@ -74,76 +119,60 @@ #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 -struct psoc4_chip_details { +#define PSOC4_FAMILY_FLAG_LEGACY 1 + +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 +205,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 +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 */ -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 +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 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 +274,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 " %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) { @@ -250,21 +288,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 +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) { - /* 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; @@ -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); - 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(®_params[0]); @@ -313,92 +366,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; - for (i = 0; i < num_bits; i += 32) { - retval = target_read_u32(target, prot_addr, &protection); + /* get family ID from SROM call */ + retval = psoc4_get_silicon_id(bank, NULL, &family_id, NULL); + if (retval != ERROR_OK) + return retval; + + /* and check with family ID from ROMTABLE */ + if (family_id != psoc4_info->family_id) { + LOG_ERROR("Family mismatch"); + return ERROR_FAIL; + } + + if (!psoc4_info->legacy_family) { + uint32_t sysreq_status; + retval = psoc4_sysreq(bank, PSOC4_CMD_SET_IMO48, 0, NULL, 0, &sysreq_status); if (retval != ERROR_OK) return retval; - prot_addr += 4; - - for (s = 0; s < 32; s++) { - if (i + s >= num_bits) - break; - bank->sectors[i + s].is_protected = (protection & (1 << s)) ? 1 : 0; + if ((sysreq_status & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { + /* This undocumented error code is returned probably when + * PSOC4_CMD_SET_IMO48 command is not implemented. + * Can be safely ignored, programming works. + */ + if (sysreq_status == PSOC4_SROM_ERR_IMO_NOT_IMPLEM) + LOG_INFO("PSOC4_CMD_SET_IMO48 is not implemented on this device."); + else { + LOG_ERROR("sysreq error 0x%" PRIx32, sysreq_status); + return ERROR_FAIL; + } } } - retval = psoc4_get_silicon_id(target, NULL, &(psoc4_info->chip_protection)); - return retval; + return ERROR_OK; } -static int psoc4_mass_erase(struct flash_bank *bank) +static int psoc4_protect_check(struct flash_bank *bank) { struct target *target = bank->target; - int i; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; + uint32_t prot_addr = PSOC4_SFLASH_MACRO0; + int retval; + 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, - ¶m, sizeof(param)); + ¶m, sizeof(param), NULL); 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); - LOG_ERROR("Only mass erase available"); + LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'"); 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; - 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 +578,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 +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) { - 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 +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) - 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 +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; - 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; @@ -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; - 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 +785,35 @@ 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 (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 +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) { + 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 (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; - 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; } diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index d443b014..5d6dcede 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -1,4 +1,4 @@ -# script for Cypress PSoC 41xx/42xx family +# script for Cypress PSoC 4 devices # # 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. -# 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. @@ -66,11 +72,34 @@ if {![using_hla]} { 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 } { - 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 @@ -87,17 +116,42 @@ proc ocd_process_reset_inner { MODE } { 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 - 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 { - 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 @@ -127,7 +181,14 @@ proc ocd_process_reset_inner { MODE } { 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 @@ -135,7 +196,9 @@ proc ocd_process_reset_inner { MODE } { 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"