2022-08-30 10:01:12 -05:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2022-06-26 17:53:35 -05:00
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2005 by Dominic Rath *
|
|
|
|
* Dominic.Rath@gmx.de *
|
|
|
|
* *
|
|
|
|
* Copyright (C) 2008 by Spencer Oliver *
|
|
|
|
* spen@spen-soft.co.uk *
|
|
|
|
* *
|
|
|
|
* Copyright (C) 2011 by Andreas Fritiofson *
|
|
|
|
* andreas.fritiofson@gmail.com *
|
|
|
|
* *
|
|
|
|
* Copyright (C) 2014 by Tomas Vanek (PSoC 4 support derived from STM32) *
|
|
|
|
* vanekt@fbl.cz *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "imp.h"
|
|
|
|
#include <helper/binarybuffer.h>
|
|
|
|
#include <jtag/jtag.h>
|
|
|
|
#include <target/algorithm.h>
|
|
|
|
#include <target/armv7m.h>
|
|
|
|
|
2020-07-11 17:00:47 -05:00
|
|
|
/* device documents:
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
PSoC(R) 4: PSoC 4200 Family Datasheet
|
|
|
|
Document Number: 001-87197 Rev. *B Revised August 29, 2013
|
|
|
|
|
|
|
|
PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM
|
2016-08-26 14:03:27 -05:00
|
|
|
Document No. 001-85634 Rev. *E June 28, 2016
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
PSoC(R) 4 Registers TRM Spec.
|
|
|
|
Document No. 001-85847 Rev. *A June 25, 2013
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
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
|
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
CY8C41xx, CY8C42xx Programming Specifications
|
|
|
|
Document No. 001-81799 Rev. *C March 4, 2014
|
2016-08-26 14:03:27 -05:00
|
|
|
|
|
|
|
CYBL10x6x, CY8C4127_BL, CY8C4247_BL Programming Specifications
|
|
|
|
Document No. 001-91508 Rev. *B September 22, 2014
|
2018-01-06 05:10:12 -06:00
|
|
|
|
|
|
|
http://dmitry.gr/index.php?r=05.Projects&proj=24.%20PSoC4%20confidential
|
2014-09-08 03:34:10 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* register locations */
|
2016-08-26 14:03:27 -05:00
|
|
|
#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
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
|
|
|
|
/* constants */
|
2018-02-21 06:54:44 -06:00
|
|
|
#define PSOC4_SFLASH_MACRO_SIZE 0x800
|
2016-08-26 14:03:27 -05:00
|
|
|
#define PSOC4_ROWS_PER_MACRO 512
|
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
#define PSOC4_SROM_KEY1 0xb6
|
|
|
|
#define PSOC4_SROM_KEY2 0xd3
|
|
|
|
#define PSOC4_SROM_SYSREQ_BIT (1<<31)
|
|
|
|
#define PSOC4_SROM_HMASTER_BIT (1<<30)
|
|
|
|
#define PSOC4_SROM_PRIVILEGED_BIT (1<<28)
|
|
|
|
#define PSOC4_SROM_STATUS_SUCCEEDED 0xa0000000
|
|
|
|
#define PSOC4_SROM_STATUS_FAILED 0xf0000000
|
2016-08-26 14:03:27 -05:00
|
|
|
#define PSOC4_SROM_STATUS_MASK 0xf0000000
|
|
|
|
|
|
|
|
/* not documented in any TRM */
|
|
|
|
#define PSOC4_SROM_ERR_IMO_NOT_IMPLEM 0xf0000013
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
#define PSOC4_CMD_GET_SILICON_ID 0
|
|
|
|
#define PSOC4_CMD_LOAD_LATCH 4
|
|
|
|
#define PSOC4_CMD_WRITE_ROW 5
|
|
|
|
#define PSOC4_CMD_PROGRAM_ROW 6
|
|
|
|
#define PSOC4_CMD_ERASE_ALL 0xa
|
|
|
|
#define PSOC4_CMD_CHECKSUM 0xb
|
|
|
|
#define PSOC4_CMD_WRITE_PROTECTION 0xd
|
2016-08-26 14:03:27 -05:00
|
|
|
#define PSOC4_CMD_SET_IMO48 0x15
|
|
|
|
#define PSOC4_CMD_WRITE_SFLASH_ROW 0x18
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
#define PSOC4_CHIP_PROT_VIRGIN 0x0
|
|
|
|
#define PSOC4_CHIP_PROT_OPEN 0x1
|
|
|
|
#define PSOC4_CHIP_PROT_PROTECTED 0x2
|
|
|
|
#define PSOC4_CHIP_PROT_KILL 0x4
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
#define PSOC4_ROMTABLE_DESIGNER_CHECK 0xb4
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
#define PSOC4_FAMILY_FLAG_LEGACY 1
|
|
|
|
|
|
|
|
struct psoc4_chip_family {
|
2014-09-08 03:34:10 -05:00
|
|
|
uint16_t id;
|
2016-08-26 14:03:27 -05:00
|
|
|
const char *name;
|
|
|
|
uint32_t flags;
|
2014-09-08 03:34:10 -05:00
|
|
|
};
|
|
|
|
|
2020-10-28 17:27:02 -05:00
|
|
|
static const struct psoc4_chip_family psoc4_families[] = {
|
2016-08-26 14:03:27 -05:00
|
|
|
{ 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 }
|
2014-09-08 03:34:10 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct psoc4_flash_bank {
|
2015-02-25 15:21:58 -06:00
|
|
|
uint32_t row_size;
|
2014-09-08 03:34:10 -05:00
|
|
|
uint32_t user_bank_size;
|
2020-06-07 10:00:13 -05:00
|
|
|
unsigned int num_macros;
|
2016-08-26 14:03:27 -05:00
|
|
|
bool probed;
|
2015-02-25 15:21:58 -06:00
|
|
|
uint8_t cmd_program_row;
|
2016-08-26 14:03:27 -05:00
|
|
|
uint16_t family_id;
|
|
|
|
bool legacy_family;
|
|
|
|
uint32_t cpuss_sysreq_addr;
|
|
|
|
uint32_t cpuss_sysarg_addr;
|
|
|
|
uint32_t spcif_geometry_addr;
|
2014-09-08 03:34:10 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
static const struct psoc4_chip_family *psoc4_family_by_id(uint16_t family_id)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
2016-08-26 14:03:27 -05:00
|
|
|
const struct psoc4_chip_family *p = psoc4_families;
|
|
|
|
while (p->id && p->id != family_id)
|
|
|
|
p++;
|
|
|
|
|
|
|
|
return p;
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *psoc4_decode_chip_protection(uint8_t protection)
|
|
|
|
{
|
|
|
|
switch (protection) {
|
|
|
|
case PSOC4_CHIP_PROT_VIRGIN:
|
|
|
|
return "protection VIRGIN";
|
|
|
|
case PSOC4_CHIP_PROT_OPEN:
|
|
|
|
return "protection open";
|
|
|
|
case PSOC4_CHIP_PROT_PROTECTED:
|
|
|
|
return "PROTECTED";
|
|
|
|
case PSOC4_CHIP_PROT_KILL:
|
|
|
|
return "protection KILL";
|
|
|
|
default:
|
|
|
|
LOG_WARNING("Unknown protection state 0x%02" PRIx8 "", protection);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* flash bank <name> psoc <base> <size> 0 0 <target#>
|
|
|
|
*/
|
|
|
|
FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
|
|
|
|
{
|
|
|
|
struct psoc4_flash_bank *psoc4_info;
|
|
|
|
|
|
|
|
if (CMD_ARGC < 6)
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
|
|
|
psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank));
|
|
|
|
|
|
|
|
bank->driver_priv = psoc4_info;
|
2016-08-26 14:03:27 -05:00
|
|
|
bank->default_padded_value = bank->erased_value = 0x00;
|
2014-09-08 03:34:10 -05:00
|
|
|
psoc4_info->user_bank_size = bank->size;
|
2016-08-26 14:03:27 -05:00
|
|
|
psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* PSoC 4 system ROM request
|
|
|
|
* Setting SROM_SYSREQ_BIT in CPUSS_SYSREQ register runs NMI service
|
|
|
|
* in sysrem ROM. Algorithm just waits for NMI to finish.
|
|
|
|
* When sysreq_params_size == 0 only one parameter is passed in CPUSS_SYSARG register.
|
|
|
|
* Otherwise address of memory parameter block is set in CPUSS_SYSARG
|
|
|
|
* and the first parameter is written to the first word of parameter block
|
|
|
|
*/
|
2016-08-26 14:03:27 -05:00
|
|
|
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)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
2016-08-26 14:03:27 -05:00
|
|
|
struct target *target = bank->target;
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
struct working_area *sysreq_wait_algorithm;
|
|
|
|
struct working_area *sysreq_mem;
|
|
|
|
|
|
|
|
struct reg_param reg_params[1];
|
|
|
|
struct armv7m_algorithm armv7m_info;
|
|
|
|
|
|
|
|
int retval = ERROR_OK;
|
|
|
|
|
|
|
|
uint32_t param1 = PSOC4_SROM_KEY1
|
|
|
|
| ((PSOC4_SROM_KEY2 + cmd) << 8)
|
|
|
|
| (cmd_param << 16);
|
|
|
|
|
|
|
|
static uint8_t psoc4_sysreq_wait_code[] = {
|
|
|
|
/* system request NMI is served immediately after algo run
|
|
|
|
now we are done: break */
|
|
|
|
0x00, 0xbe, /* bkpt 0 */
|
|
|
|
};
|
|
|
|
|
|
|
|
const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4;
|
|
|
|
/* stack must be aligned */
|
2016-08-26 14:03:27 -05:00
|
|
|
const int stack_size = 256;
|
|
|
|
/* tested stack sizes on PSoC4200:
|
2014-09-08 03:34:10 -05:00
|
|
|
ERASE_ALL 144
|
|
|
|
PROGRAM_ROW 112
|
|
|
|
other sysreq 68
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* allocate area for sysreq wait code and stack */
|
|
|
|
if (target_alloc_working_area(target, code_words * 4 + stack_size,
|
|
|
|
&sysreq_wait_algorithm) != ERROR_OK) {
|
|
|
|
LOG_DEBUG("no working area for sysreq code");
|
|
|
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
2016-02-28 14:21:40 -06:00
|
|
|
}
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
/* Write the code */
|
|
|
|
retval = target_write_buffer(target,
|
|
|
|
sysreq_wait_algorithm->address,
|
|
|
|
sizeof(psoc4_sysreq_wait_code),
|
|
|
|
psoc4_sysreq_wait_code);
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
/* we already allocated the writing code, but failed to get a
|
|
|
|
* buffer, free the algorithm */
|
|
|
|
goto cleanup_algo;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sysreq_params_size) {
|
2018-02-14 12:47:06 -06:00
|
|
|
LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " size %" PRIu32,
|
|
|
|
cmd, cmd_param, param1, sysreq_params_size);
|
2014-09-08 03:34:10 -05:00
|
|
|
/* Allocate memory for sysreq_params */
|
|
|
|
retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem);
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
LOG_WARNING("no working area for sysreq parameters");
|
|
|
|
|
|
|
|
/* we already allocated the writing code, but failed to get a
|
|
|
|
* buffer, free the algorithm */
|
|
|
|
retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
|
|
goto cleanup_algo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write sysreq_params */
|
2016-08-26 14:03:27 -05:00
|
|
|
target_buffer_set_u32(target, (uint8_t *)sysreq_params, param1);
|
2014-09-08 03:34:10 -05:00
|
|
|
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 */
|
2016-08-26 14:03:27 -05:00
|
|
|
retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, sysreq_mem->address);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
goto cleanup_mem;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* Sysreq without memory block of parameters */
|
2016-08-26 14:03:27 -05:00
|
|
|
LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32,
|
|
|
|
cmd, cmd_param, param1);
|
2014-09-08 03:34:10 -05:00
|
|
|
/* Set register parameter */
|
2016-08-26 14:03:27 -05:00
|
|
|
retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, param1);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
goto cleanup_mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
|
|
|
armv7m_info.core_mode = ARM_MODE_THREAD;
|
|
|
|
|
|
|
|
/* sysreq stack */
|
|
|
|
init_reg_param(®_params[0], "sp", 32, PARAM_OUT);
|
|
|
|
buf_set_u32(reg_params[0].value, 0, 32,
|
|
|
|
sysreq_wait_algorithm->address + sysreq_wait_algorithm->size);
|
|
|
|
|
|
|
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
2021-07-03 11:51:20 -05:00
|
|
|
if (!armv7m) {
|
2014-09-08 03:34:10 -05:00
|
|
|
/* something is very wrong if armv7m is NULL */
|
|
|
|
LOG_ERROR("unable to get armv7m target");
|
2018-02-14 12:47:06 -06:00
|
|
|
retval = ERROR_FAIL;
|
2014-09-08 03:34:10 -05:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set SROM request */
|
2016-08-26 14:03:27 -05:00
|
|
|
retval = target_write_u32(target, psoc4_info->cpuss_sysreq_addr,
|
2014-09-08 03:34:10 -05:00
|
|
|
PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd);
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Execute wait code */
|
|
|
|
retval = target_run_algorithm(target, 0, NULL,
|
2020-08-24 04:42:15 -05:00
|
|
|
ARRAY_SIZE(reg_params), reg_params,
|
2014-09-08 03:34:10 -05:00
|
|
|
sysreq_wait_algorithm->address, 0, 1000, &armv7m_info);
|
2016-08-26 14:03:27 -05:00
|
|
|
if (retval != ERROR_OK) {
|
2014-09-08 03:34:10 -05:00
|
|
|
LOG_ERROR("sysreq wait code execution failed");
|
2016-08-26 14:03:27 -05:00
|
|
|
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;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2014-09-08 03:34:10 -05:00
|
|
|
cleanup:
|
|
|
|
destroy_reg_param(®_params[0]);
|
|
|
|
|
|
|
|
cleanup_mem:
|
|
|
|
if (sysreq_params_size)
|
|
|
|
target_free_working_area(target, sysreq_mem);
|
|
|
|
|
|
|
|
cleanup_algo:
|
|
|
|
target_free_working_area(target, sysreq_wait_algorithm);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* helper routine to get silicon ID from a PSoC 4 chip */
|
2016-08-26 14:03:27 -05:00
|
|
|
static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, uint16_t *family_id, uint8_t *protection)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
2016-08-26 14:03:27 -05:00
|
|
|
struct target *target = bank->target;
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
uint32_t part0, part1;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
int retval = psoc4_sysreq(bank, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0, &part0);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
if ((part0 & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) {
|
|
|
|
LOG_ERROR("sysreq error 0x%" PRIx32, part0);
|
2014-09-08 03:34:10 -05:00
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
retval = target_read_u32(target, psoc4_info->cpuss_sysreq_addr, &part1);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
/* build ID as Cypress sw does:
|
|
|
|
* bit 31..16 silicon ID
|
|
|
|
* bit 15..8 revision ID (so far 0x11 for all devices)
|
2020-07-11 17:00:47 -05:00
|
|
|
* bit 7..0 family ID (lowest 8 bits)
|
2016-08-26 14:03:27 -05:00
|
|
|
*/
|
2014-09-08 03:34:10 -05:00
|
|
|
if (silicon_id)
|
2016-08-26 14:03:27 -05:00
|
|
|
*silicon_id = ((part0 & 0x0000ffff) << 16)
|
|
|
|
| ((part0 & 0x00ff0000) >> 8)
|
|
|
|
| (part1 & 0x000000ff);
|
|
|
|
|
|
|
|
if (family_id)
|
|
|
|
*family_id = part1 & 0x0fff;
|
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
if (protection)
|
2016-08-26 14:03:27 -05:00
|
|
|
*protection = (part1 >> 12) & 0x0f;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
return ERROR_OK;
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
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)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
|
|
|
struct target *target = bank->target;
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
if (target->state != TARGET_HALTED) {
|
|
|
|
LOG_ERROR("Target not halted");
|
|
|
|
return ERROR_TARGET_NOT_HALTED;
|
|
|
|
}
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
uint16_t family_id;
|
|
|
|
int retval;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
/* 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);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
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;
|
|
|
|
}
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
return ERROR_OK;
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
static int psoc4_protect_check(struct flash_bank *bank)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
|
|
|
struct target *target = bank->target;
|
2016-08-26 14:03:27 -05:00
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
uint32_t prot_addr = PSOC4_SFLASH_MACRO0;
|
|
|
|
int retval;
|
|
|
|
uint8_t bf[PSOC4_ROWS_PER_MACRO/8];
|
2020-06-07 10:00:13 -05:00
|
|
|
unsigned int s = 0;
|
2016-08-26 14:03:27 -05:00
|
|
|
|
2020-06-07 10:00:13 -05:00
|
|
|
for (unsigned int m = 0; m < psoc4_info->num_macros; m++, prot_addr += PSOC4_SFLASH_MACRO_SIZE) {
|
2016-08-26 14:03:27 -05:00
|
|
|
retval = target_read_memory(target, prot_addr, 4, PSOC4_ROWS_PER_MACRO/32, bf);
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
2020-06-07 10:00:13 -05:00
|
|
|
for (unsigned int i = 0; i < PSOC4_ROWS_PER_MACRO && s < bank->num_sectors; i++, s++)
|
2016-08-26 14:03:27 -05:00
|
|
|
bank->sectors[s].is_protected = bf[i/8] & (1 << (i%8)) ? 1 : 0;
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int psoc4_mass_erase(struct flash_bank *bank)
|
|
|
|
{
|
|
|
|
int retval = psoc4_flash_prepare(bank);
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
/* Call "Erase All" system ROM API */
|
2016-08-26 14:03:27 -05:00
|
|
|
uint32_t param = 0;
|
2021-05-07 05:02:23 -05:00
|
|
|
return psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL,
|
2014-09-08 03:34:10 -05:00
|
|
|
0,
|
2016-08-26 14:03:27 -05:00
|
|
|
¶m, sizeof(param), NULL);
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-07 10:00:13 -05:00
|
|
|
static int psoc4_erase(struct flash_bank *bank, unsigned int first,
|
|
|
|
unsigned int last)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
if (psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW) {
|
|
|
|
LOG_INFO("Autoerase enabled, erase command ignored");
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((first == 0) && (last == (bank->num_sectors - 1)))
|
|
|
|
return psoc4_mass_erase(bank);
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'");
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-07 10:00:13 -05:00
|
|
|
static int psoc4_protect(struct flash_bank *bank, int set, unsigned int first,
|
|
|
|
unsigned int last)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
|
|
|
struct target *target = bank->target;
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
if (!psoc4_info->probed)
|
2014-09-08 03:34:10 -05:00
|
|
|
return ERROR_FAIL;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
int retval = psoc4_flash_prepare(bank);
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
uint32_t *sysrq_buffer = NULL;
|
|
|
|
const int param_sz = 8;
|
|
|
|
int chip_prot = PSOC4_CHIP_PROT_OPEN;
|
2020-06-07 10:00:13 -05:00
|
|
|
unsigned int i;
|
|
|
|
unsigned int num_bits = bank->num_sectors;
|
2016-08-26 14:03:27 -05:00
|
|
|
|
|
|
|
if (num_bits > PSOC4_ROWS_PER_MACRO)
|
|
|
|
num_bits = PSOC4_ROWS_PER_MACRO;
|
|
|
|
|
|
|
|
int prot_sz = num_bits / 8;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2018-02-21 06:54:44 -06:00
|
|
|
sysrq_buffer = malloc(param_sz + prot_sz);
|
2021-07-03 11:51:20 -05:00
|
|
|
if (!sysrq_buffer) {
|
2014-09-08 03:34:10 -05:00
|
|
|
LOG_ERROR("no memory for row buffer");
|
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
for (i = first; i <= last && i < bank->num_sectors; i++)
|
2014-09-08 03:34:10 -05:00
|
|
|
bank->sectors[i].is_protected = set;
|
|
|
|
|
2020-06-07 10:00:13 -05:00
|
|
|
for (unsigned int m = 0, sect = 0; m < psoc4_info->num_macros; m++) {
|
2016-08-26 14:03:27 -05:00
|
|
|
uint8_t *p = (uint8_t *)(sysrq_buffer + 2);
|
2018-02-21 06:54:44 -06:00
|
|
|
memset(p, 0, prot_sz);
|
|
|
|
for (i = 0; i < num_bits && sect < bank->num_sectors; i++, sect++) {
|
|
|
|
if (bank->sectors[sect].is_protected)
|
2016-08-26 14:03:27 -05:00
|
|
|
p[i/8] |= 1 << (i%8);
|
|
|
|
}
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
/* 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 */
|
2018-02-21 06:54:44 -06:00
|
|
|
sysrq_buffer, param_sz + prot_sz,
|
2016-08-26 14:03:27 -05:00
|
|
|
NULL);
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
break;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
/* 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;
|
|
|
|
}
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2020-08-17 03:08:35 -05:00
|
|
|
free(sysrq_buffer);
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
psoc4_protect_check(bank);
|
2014-09-08 03:34:10 -05:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(psoc4_handle_flash_autoerase_command)
|
|
|
|
{
|
|
|
|
if (CMD_ARGC < 1)
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
|
|
|
struct flash_bank *bank;
|
|
|
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
2021-07-03 09:47:35 -05:00
|
|
|
if (retval != ERROR_OK)
|
2014-09-08 03:34:10 -05:00
|
|
|
return retval;
|
|
|
|
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
bool enable = psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW;
|
|
|
|
|
|
|
|
if (CMD_ARGC >= 2)
|
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
|
|
|
|
|
|
|
|
if (enable) {
|
|
|
|
psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW;
|
|
|
|
LOG_INFO("Flash auto-erase enabled, non mass erase commands will be ignored.");
|
|
|
|
} else {
|
|
|
|
psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW;
|
|
|
|
LOG_INFO("Flash auto-erase disabled. Use psoc mass_erase before flash programming.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
|
|
|
|
uint32_t offset, uint32_t count)
|
|
|
|
{
|
|
|
|
struct target *target = bank->target;
|
2016-08-26 14:03:27 -05:00
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
2014-09-08 03:34:10 -05:00
|
|
|
uint32_t *sysrq_buffer = NULL;
|
|
|
|
const int param_sz = 8;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
int retval = psoc4_flash_prepare(bank);
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
sysrq_buffer = malloc(param_sz + psoc4_info->row_size);
|
2021-07-03 11:51:20 -05:00
|
|
|
if (!sysrq_buffer) {
|
2014-09-08 03:34:10 -05:00
|
|
|
LOG_ERROR("no memory for row buffer");
|
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *row_buffer = (uint8_t *)sysrq_buffer + param_sz;
|
|
|
|
uint32_t row_num = offset / psoc4_info->row_size;
|
|
|
|
uint32_t row_offset = offset - row_num * psoc4_info->row_size;
|
|
|
|
if (row_offset)
|
2016-08-26 14:03:27 -05:00
|
|
|
memset(row_buffer, bank->default_padded_value, row_offset);
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
while (count) {
|
|
|
|
uint32_t chunk_size = psoc4_info->row_size - row_offset;
|
|
|
|
if (chunk_size > count) {
|
|
|
|
chunk_size = count;
|
2016-08-26 14:03:27 -05:00
|
|
|
memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size);
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
memcpy(row_buffer + row_offset, buffer, chunk_size);
|
2015-02-25 15:21:58 -06:00
|
|
|
LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "",
|
2014-09-08 03:34:10 -05:00
|
|
|
offset, row_offset, chunk_size);
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO;
|
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
/* Call "Load Latch" system ROM API */
|
2016-08-26 14:03:27 -05:00
|
|
|
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);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Call "Program Row" or "Write Row" system ROM API */
|
|
|
|
uint32_t sysrq_param;
|
2016-08-26 14:03:27 -05:00
|
|
|
retval = psoc4_sysreq(bank, psoc4_info->cmd_program_row,
|
2014-09-08 03:34:10 -05:00
|
|
|
row_num & 0xffff,
|
2016-08-26 14:03:27 -05:00
|
|
|
&sysrq_param, sizeof(sysrq_param),
|
|
|
|
NULL);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
buffer += chunk_size;
|
|
|
|
row_num++;
|
|
|
|
row_offset = 0;
|
|
|
|
count -= chunk_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
2020-08-17 03:08:35 -05:00
|
|
|
free(sysrq_buffer);
|
2014-09-08 03:34:10 -05:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-06 05:10:12 -06:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-08 03:34:10 -05:00
|
|
|
static int psoc4_probe(struct flash_bank *bank)
|
|
|
|
{
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
struct target *target = bank->target;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
int retval;
|
|
|
|
uint16_t family_id;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
psoc4_info->probed = false;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
retval = psoc4_get_family(target, &family_id);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
const struct psoc4_chip_family *family = psoc4_family_by_id(family_id);
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
if (family->id == 0) {
|
|
|
|
LOG_ERROR("Cannot identify PSoC 4 family.");
|
2014-09-08 03:34:10 -05:00
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
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;
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
uint32_t spcif_geometry;
|
|
|
|
retval = target_read_u32(target, psoc4_info->spcif_geometry_addr, &spcif_geometry);
|
2014-09-08 03:34:10 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
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++;
|
2014-09-08 03:34:10 -05:00
|
|
|
}
|
|
|
|
|
2021-08-07 13:55:30 -05:00
|
|
|
LOG_DEBUG("SPCIF geometry: %" PRIu32 " KiB flash, row %" PRIu32 " bytes.",
|
2016-08-26 14:03:27 -05:00
|
|
|
flash_size_in_kb, row_size);
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
/* 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 (psoc4_info->user_bank_size) {
|
|
|
|
LOG_INFO("ignoring flash probed value, using configured bank size");
|
|
|
|
flash_size_in_kb = psoc4_info->user_bank_size / 1024;
|
|
|
|
}
|
|
|
|
|
2023-05-27 08:56:44 -05:00
|
|
|
char macros_txt[22] = "";
|
2016-08-26 14:03:27 -05:00
|
|
|
if (num_macros > 1)
|
|
|
|
snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros);
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2021-08-07 13:55:30 -05:00
|
|
|
LOG_INFO("flash size = %" PRIu32 " KiB%s", flash_size_in_kb, macros_txt);
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
/* calculate number of pages */
|
2015-02-25 15:21:58 -06:00
|
|
|
uint32_t num_rows = flash_size_in_kb * 1024 / row_size;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
/* 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!");
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2018-01-06 05:10:12 -06:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-17 03:08:35 -05:00
|
|
|
free(bank->sectors);
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
psoc4_info->family_id = family_id;
|
|
|
|
psoc4_info->num_macros = num_macros;
|
|
|
|
psoc4_info->row_size = row_size;
|
|
|
|
bank->base = 0x00000000;
|
2015-02-25 15:21:58 -06:00
|
|
|
bank->size = num_rows * row_size;
|
2014-09-08 03:34:10 -05:00
|
|
|
bank->num_sectors = num_rows;
|
2016-08-26 14:03:27 -05:00
|
|
|
bank->sectors = alloc_block_array(0, row_size, num_rows);
|
2021-07-03 11:51:20 -05:00
|
|
|
if (!bank->sectors)
|
2016-08-26 14:03:27 -05:00
|
|
|
return ERROR_FAIL;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
LOG_DEBUG("flash bank set %" PRIu32 " rows", num_rows);
|
|
|
|
psoc4_info->probed = true;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int psoc4_auto_probe(struct flash_bank *bank)
|
|
|
|
{
|
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
if (psoc4_info->probed)
|
|
|
|
return ERROR_OK;
|
|
|
|
return psoc4_probe(bank);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-23 03:47:17 -05:00
|
|
|
static int get_psoc4_info(struct flash_bank *bank, struct command_invocation *cmd)
|
2014-09-08 03:34:10 -05:00
|
|
|
{
|
2016-08-26 14:03:27 -05:00
|
|
|
struct target *target = bank->target;
|
2014-09-08 03:34:10 -05:00
|
|
|
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
if (!psoc4_info->probed)
|
2014-09-08 03:34:10 -05:00
|
|
|
return ERROR_FAIL;
|
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
const struct psoc4_chip_family *family = psoc4_family_by_id(psoc4_info->family_id);
|
|
|
|
uint32_t size_in_kb = bank->size / 1024;
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
if (target->state != TARGET_HALTED) {
|
2021-04-23 03:47:17 -05:00
|
|
|
command_print_sameline(cmd, "%s, flash %" PRIu32 " kb"
|
2016-08-26 14:03:27 -05:00
|
|
|
" (halt target to see details)", family->name, size_in_kb);
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t silicon_id;
|
|
|
|
uint16_t family_id;
|
|
|
|
uint8_t protection;
|
|
|
|
|
2021-04-23 03:47:17 -05:00
|
|
|
int retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection);
|
2016-08-26 14:03:27 -05:00
|
|
|
if (retval != ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
if (family_id != psoc4_info->family_id)
|
2021-04-23 03:47:17 -05:00
|
|
|
command_print_sameline(cmd, "Family id mismatch 0x%02" PRIx16
|
2016-08-26 14:03:27 -05:00
|
|
|
"/0x%02" PRIx16 ", silicon id 0x%08" PRIx32,
|
|
|
|
psoc4_info->family_id, family_id, silicon_id);
|
|
|
|
else {
|
2021-04-23 03:47:17 -05:00
|
|
|
command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32 "",
|
2016-08-26 14:03:27 -05:00
|
|
|
family->name, silicon_id);
|
|
|
|
}
|
2014-09-08 03:34:10 -05:00
|
|
|
|
2016-08-26 14:03:27 -05:00
|
|
|
const char *prot_txt = psoc4_decode_chip_protection(protection);
|
2021-04-23 03:47:17 -05:00
|
|
|
command_print_sameline(cmd, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
|
2014-09-08 03:34:10 -05:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(psoc4_handle_mass_erase_command)
|
|
|
|
{
|
|
|
|
if (CMD_ARGC < 1)
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
|
|
|
struct flash_bank *bank;
|
|
|
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
2021-07-03 09:47:35 -05:00
|
|
|
if (retval != ERROR_OK)
|
2014-09-08 03:34:10 -05:00
|
|
|
return retval;
|
|
|
|
|
|
|
|
retval = psoc4_mass_erase(bank);
|
|
|
|
if (retval == ERROR_OK)
|
helper/command: change prototype of command_print/command_print_sameline
To prepare for handling TCL return values consistently, all calls
to command_print/command_print_sameline should switch to CMD as
first parameter.
Change prototype of command_print() and command_print_sameline()
to pass CMD instead of CMD_CTX.
Since the first parameter is currently not used, the change can be
done though scripts without manual coding.
This patch is created using the command:
sed -i PATTERN $(find src/ doc/ -type f)
with all the following patters:
's/\(command_print(cmd\)->ctx,/\1,/'
's/\(command_print(CMD\)_CTX,/\1,/'
's/\(command_print(struct command_\)context \*context,/\1invocation *cmd,/'
's/\(command_print_sameline(cmd\)->ctx,/\1,/'
's/\(command_print_sameline(CMD\)_CTX,/\1,/'
's/\(command_print_sameline(struct command_\)context \*context,/\1invocation *cmd,/'
This change is inspired by http://openocd.zylin.com/1815 from Paul
Fertser but is now done through scripting.
Change-Id: I3386d8f96cdc477e7a2308dd18269de3bed04385
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/5081
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
2019-04-03 03:37:24 -05:00
|
|
|
command_print(CMD, "psoc mass erase complete");
|
2014-09-08 03:34:10 -05:00
|
|
|
else
|
helper/command: change prototype of command_print/command_print_sameline
To prepare for handling TCL return values consistently, all calls
to command_print/command_print_sameline should switch to CMD as
first parameter.
Change prototype of command_print() and command_print_sameline()
to pass CMD instead of CMD_CTX.
Since the first parameter is currently not used, the change can be
done though scripts without manual coding.
This patch is created using the command:
sed -i PATTERN $(find src/ doc/ -type f)
with all the following patters:
's/\(command_print(cmd\)->ctx,/\1,/'
's/\(command_print(CMD\)_CTX,/\1,/'
's/\(command_print(struct command_\)context \*context,/\1invocation *cmd,/'
's/\(command_print_sameline(cmd\)->ctx,/\1,/'
's/\(command_print_sameline(CMD\)_CTX,/\1,/'
's/\(command_print_sameline(struct command_\)context \*context,/\1invocation *cmd,/'
This change is inspired by http://openocd.zylin.com/1815 from Paul
Fertser but is now done through scripting.
Change-Id: I3386d8f96cdc477e7a2308dd18269de3bed04385
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/5081
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
2019-04-03 03:37:24 -05:00
|
|
|
command_print(CMD, "psoc mass erase failed");
|
2014-09-08 03:34:10 -05:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const struct command_registration psoc4_exec_command_handlers[] = {
|
|
|
|
{
|
|
|
|
.name = "mass_erase",
|
|
|
|
.handler = psoc4_handle_mass_erase_command,
|
|
|
|
.mode = COMMAND_EXEC,
|
|
|
|
.usage = "bank_id",
|
|
|
|
.help = "Erase entire flash device.",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "flash_autoerase",
|
|
|
|
.handler = psoc4_handle_flash_autoerase_command,
|
|
|
|
.mode = COMMAND_EXEC,
|
|
|
|
.usage = "bank_id on|off",
|
|
|
|
.help = "Set autoerase mode for flash bank.",
|
|
|
|
},
|
|
|
|
COMMAND_REGISTRATION_DONE
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct command_registration psoc4_command_handlers[] = {
|
|
|
|
{
|
|
|
|
.name = "psoc4",
|
|
|
|
.mode = COMMAND_ANY,
|
|
|
|
.help = "PSoC 4 flash command group",
|
|
|
|
.usage = "",
|
|
|
|
.chain = psoc4_exec_command_handlers,
|
|
|
|
},
|
|
|
|
COMMAND_REGISTRATION_DONE
|
|
|
|
};
|
|
|
|
|
2018-12-13 13:53:59 -06:00
|
|
|
const struct flash_driver psoc4_flash = {
|
2014-09-08 03:34:10 -05:00
|
|
|
.name = "psoc4",
|
|
|
|
.commands = psoc4_command_handlers,
|
|
|
|
.flash_bank_command = psoc4_flash_bank_command,
|
|
|
|
.erase = psoc4_erase,
|
|
|
|
.protect = psoc4_protect,
|
|
|
|
.write = psoc4_write,
|
|
|
|
.read = default_flash_read,
|
|
|
|
.probe = psoc4_probe,
|
|
|
|
.auto_probe = psoc4_auto_probe,
|
|
|
|
.erase_check = default_flash_blank_check,
|
|
|
|
.protect_check = psoc4_protect_check,
|
|
|
|
.info = get_psoc4_info,
|
2018-02-15 03:25:50 -06:00
|
|
|
.free_driver_priv = default_flash_free_driver_priv,
|
2014-09-08 03:34:10 -05:00
|
|
|
};
|