psoc6: Run flash algorithm asynchronously to improve performance
Existing psoc6 driver starts flash algorithm for each Flash row. This is suboptimal from performance point of view, starting/stopping flash algorithm for each row adds significant overhead. This change starts flash algorithm and leaves it running asynchronously while driver performs flash operations. Performance gain is 170...250% depending on probe: flash write_image img_256k.bin | w/o this change | with this change | ----------------------------------|-----------------|------------------| KitProg2/CMSIS-DAP, SWD @ 1 MHz | 4 KiB/s | 10 KiB/s | J-Link Ultra, SWD @ 1 MHz | 17 KiB/s | 31 KiB/s | J-Link Ultra, SWD @ 4 MHz | 33 KiB/s | 57 KiB/s | Change-Id: I5bd582584b35af67600c4d197829eb7aeeec7e3f Signed-off-by: Bohdan Tymkiv <bhdt@cypress.com> Reviewed-on: http://openocd.zylin.com/4472 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz>riscv-compliance
parent
b941e2e727
commit
4440bf1fcd
|
@ -1,6 +1,6 @@
|
|||
/***************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Bohdan Tymkiv *
|
||||
* Copyright (C) 2018 by Bohdan Tymkiv *
|
||||
* bohdan.tymkiv@cypress.com bohdan200@gmail.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
@ -101,7 +101,7 @@ struct row_region {
|
|||
size_t size;
|
||||
};
|
||||
|
||||
static struct row_region safe_sflash_regions[] = {
|
||||
static const struct row_region safe_sflash_regions[] = {
|
||||
{0x16000800, 0x800}, /* SFLASH: User Data */
|
||||
{0x16001A00, 0x200}, /* SFLASH: NAR */
|
||||
{0x16005A00, 0xC00}, /* SFLASH: Public Key */
|
||||
|
@ -111,8 +111,12 @@ static struct row_region safe_sflash_regions[] = {
|
|||
#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0]))
|
||||
|
||||
static struct working_area *g_stack_area;
|
||||
/**************************************************************************************************
|
||||
* Initializes timeout_s structure with given timeout in milliseconds
|
||||
static struct armv7m_algorithm g_armv7m_info;
|
||||
|
||||
/** ***********************************************************************************************
|
||||
* @brief Initializes `struct timeout` structure with given timeout value
|
||||
* @param to pointer to `struct timeout` structure
|
||||
* @param timeout_ms timeout, in milliseconds
|
||||
*************************************************************************************************/
|
||||
static void timeout_init(struct timeout *to, long timeout_ms)
|
||||
{
|
||||
|
@ -120,17 +124,23 @@ static void timeout_init(struct timeout *to, long timeout_ms)
|
|||
to->timeout_ms = timeout_ms;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Returns true if given timeout_s object has expired
|
||||
/** ***********************************************************************************************
|
||||
* @brief Returns true if given `struct timeout` structure has expired
|
||||
* @param to pointer to `struct timeout` structure
|
||||
* @return true if timeout expired
|
||||
*************************************************************************************************/
|
||||
static bool timeout_expired(struct timeout *to)
|
||||
{
|
||||
return (timeval_ms() - to->start_time) > to->timeout_ms;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Prepares PSoC6 for running pseudo flash algorithm. This function allocates Working Area for
|
||||
* the algorithm and for CPU Stack.
|
||||
/** ***********************************************************************************************
|
||||
* @brief Starts pseudo flash algorithm and leaves it running. Function allocates working area for
|
||||
* algorithm code and CPU stack, adjusts stack pointer, uploads and starts the algorithm.
|
||||
* Algorithm (a basic infinite loop) runs asynchronously while driver performs Flash operations.
|
||||
*
|
||||
* @param target target for the algorithm
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int sromalgo_prepare(struct target *target)
|
||||
{
|
||||
|
@ -141,21 +151,42 @@ static int sromalgo_prepare(struct target *target)
|
|||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
/* Restore THUMB bit in xPSR register */
|
||||
const struct armv7m_common *cm = target_to_armv7m(target);
|
||||
hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
/* Allocate Working Area for Stack and Flash algorithm */
|
||||
hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
/* Restore THUMB bit in xPSR register */
|
||||
const struct armv7m_common *cm = target_to_armv7m(target);
|
||||
hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000);
|
||||
g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
g_armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
struct reg_param reg_params;
|
||||
init_reg_param(®_params, "sp", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size);
|
||||
|
||||
/* Write basic infinite loop algorithm to target RAM */
|
||||
hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7);
|
||||
if (hr != ERROR_OK)
|
||||
goto exit_free_wa;
|
||||
goto destroy_rp_free_wa;
|
||||
|
||||
return ERROR_OK;
|
||||
hr = target_start_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address,
|
||||
0, &g_armv7m_info);
|
||||
if (hr != ERROR_OK)
|
||||
goto destroy_rp_free_wa;
|
||||
|
||||
destroy_reg_param(®_params);
|
||||
|
||||
return hr;
|
||||
|
||||
destroy_rp_free_wa:
|
||||
/* Something went wrong, do some cleanup */
|
||||
destroy_reg_param(®_params);
|
||||
|
||||
exit_free_wa:
|
||||
/* Something went wrong, free allocated area */
|
||||
if (g_stack_area) {
|
||||
target_free_working_area(target, g_stack_area);
|
||||
g_stack_area = NULL;
|
||||
|
@ -164,65 +195,48 @@ exit_free_wa:
|
|||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Releases working area
|
||||
/** ***********************************************************************************************
|
||||
* @brief Stops running flash algorithm and releases associated resources.
|
||||
* This function is also used for cleanup in case of errors so g_stack_area may be NULL.
|
||||
* These cases have to be handled gracefully.
|
||||
*
|
||||
* @param target current target
|
||||
*************************************************************************************************/
|
||||
static int sromalgo_release(struct target *target)
|
||||
static void sromalgo_release(struct target *target)
|
||||
{
|
||||
int hr = ERROR_OK;
|
||||
|
||||
/* Free Stack/Flash algorithm working area */
|
||||
if (g_stack_area) {
|
||||
hr = target_free_working_area(target, g_stack_area);
|
||||
g_stack_area = NULL;
|
||||
/* Stop flash algorithm if it is running */
|
||||
if (target->running_alg) {
|
||||
hr = target_halt(target);
|
||||
if (hr != ERROR_OK)
|
||||
goto exit_free_wa;
|
||||
|
||||
hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0,
|
||||
IPC_TIMEOUT_MS, &g_armv7m_info);
|
||||
if (hr != ERROR_OK)
|
||||
goto exit_free_wa;
|
||||
}
|
||||
|
||||
return hr;
|
||||
exit_free_wa:
|
||||
/* Free Stack/Flash algorithm working area */
|
||||
target_free_working_area(target, g_stack_area);
|
||||
g_stack_area = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Runs pseudo flash algorithm. Algorithm itself consist of couple of NOPs followed by BKPT
|
||||
* instruction. The trick here is that NMI has already been posted to CM0 via IPC structure
|
||||
* prior to calling this function. CM0 will immediately jump to NMI handler and execute
|
||||
* SROM API code.
|
||||
* This approach is borrowed from PSoC4 Flash Driver.
|
||||
*************************************************************************************************/
|
||||
static int sromalgo_run(struct target *target)
|
||||
{
|
||||
int hr;
|
||||
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
struct reg_param reg_params;
|
||||
init_reg_param(®_params, "sp", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size);
|
||||
|
||||
/* mov r8, r8; mov r8, r8 */
|
||||
hr = target_write_u32(target, g_stack_area->address + 0, 0x46C046C0);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
/* mov r8, r8; bkpt #0 */
|
||||
hr = target_write_u32(target, g_stack_area->address + 4, 0xBE0046C0);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
hr = target_run_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address,
|
||||
0, SROMAPI_CALL_TIMEOUT_MS, &armv7m_info);
|
||||
|
||||
destroy_reg_param(®_params);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Waits for expected IPC lock status.
|
||||
* PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API.
|
||||
* IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the
|
||||
* system will use same IPC thus corrupting our data. Locking is performed by ipc_acquire(), this
|
||||
* function ensures that IPC is actually in expected state
|
||||
/** ***********************************************************************************************
|
||||
* @brief Waits for expected IPC lock status. PSoC6 uses IPC structures for inter-core
|
||||
* communication. Same IPCs are used to invoke SROM API. IPC structure must be locked prior to
|
||||
* invoking any SROM API. This ensures nothing else in the system will use same IPC thus corrupting
|
||||
* our data. Locking is performed by ipc_acquire(), this function ensures that IPC is actually
|
||||
* in expected state
|
||||
*
|
||||
* @param target current target
|
||||
* @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access
|
||||
* @param lock_expected expected lock status
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected)
|
||||
{
|
||||
|
@ -258,11 +272,15 @@ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_
|
|||
return ERROR_TARGET_TIMEOUT;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Acquires IPC structure
|
||||
* PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API.
|
||||
* IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the
|
||||
* system will use same IPC thus corrupting our data. This function locks the IPC.
|
||||
/** ***********************************************************************************************
|
||||
* @brief Acquires IPC structure. PSoC6 uses IPC structures for inter-core communication.
|
||||
* Same IPCs are used to invoke SROM API. IPC structure must be locked prior to invoking any SROM API.
|
||||
* This ensures nothing else in the system will use same IPC thus corrupting our data.
|
||||
* This function locks the IPC.
|
||||
*
|
||||
* @param target current target
|
||||
* @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP access
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int ipc_acquire(struct target *target, char ipc_id)
|
||||
{
|
||||
|
@ -303,8 +321,14 @@ static int ipc_acquire(struct target *target, char ipc_id)
|
|||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Invokes SROM API functions which are responsible for Flash operations
|
||||
/** ***********************************************************************************************
|
||||
* @brief Invokes SROM API functions which are responsible for Flash operations
|
||||
*
|
||||
* @param target current target
|
||||
* @param req_and_params requect id of the function to invoke
|
||||
* @param working_area address of memory buffer in target's memory space for SROM API parameters
|
||||
* @param data_out pointer to variable which will be populated with execution status
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int call_sromapi(struct target *target,
|
||||
uint32_t req_and_params,
|
||||
|
@ -336,10 +360,6 @@ static int call_sromapi(struct target *target,
|
|||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
hr = sromalgo_run(target);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
/* Poll lock status */
|
||||
hr = ipc_poll_lock_stat(target, IPC_ID, false);
|
||||
if (hr != ERROR_OK)
|
||||
|
@ -365,8 +385,12 @@ static int call_sromapi(struct target *target,
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Retrieves SiliconID and Protection status of the target device
|
||||
/** ***********************************************************************************************
|
||||
* @brief Retrieves SiliconID and Protection status of the target device
|
||||
* @param target current target
|
||||
* @param si_id pointer to variable, will be populated with SiliconID
|
||||
* @param protection pointer to variable, will be populated with protection status
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection)
|
||||
{
|
||||
|
@ -375,17 +399,17 @@ static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *prote
|
|||
|
||||
hr = sromalgo_prepare(target);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
goto exit;
|
||||
|
||||
/* Read FamilyID and Revision */
|
||||
hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
goto exit;
|
||||
|
||||
/* Read SiliconID and Protection */
|
||||
hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
goto exit;
|
||||
|
||||
*si_id = (siid_prot & 0x0000FFFF) << 16;
|
||||
*si_id |= (family_rev & 0x00FF0000) >> 8;
|
||||
|
@ -393,12 +417,15 @@ static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *prote
|
|||
|
||||
*protection = (siid_prot & 0x000F0000) >> 0x10;
|
||||
|
||||
hr = sromalgo_release(target);
|
||||
return hr;
|
||||
exit:
|
||||
sromalgo_release(target);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Translates Protection status to openocd-friendly boolean value
|
||||
/** ***********************************************************************************************
|
||||
* @brief Translates Protection status to openocd-friendly boolean value
|
||||
* @param bank current flash bank
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
|
@ -429,8 +456,9 @@ static int psoc6_protect_check(struct flash_bank *bank)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Life Cycle transition is not currently supported
|
||||
/** ***********************************************************************************************
|
||||
* @brief Dummy function, Life Cycle transition is not currently supported
|
||||
* @return ERROR_OK always
|
||||
*************************************************************************************************/
|
||||
static int psoc6_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
|
@ -443,8 +471,10 @@ static int psoc6_protect(struct flash_bank *bank, int set, int first, int last)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Translates Protection status to string
|
||||
/** ***********************************************************************************************
|
||||
* @brief Translates Protection status to string
|
||||
* @param protection protection value
|
||||
* @return pointer to const string describintg protection status
|
||||
*************************************************************************************************/
|
||||
static const char *protection_to_str(uint8_t protection)
|
||||
{
|
||||
|
@ -468,8 +498,12 @@ static const char *protection_to_str(uint8_t protection)
|
|||
}
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Displays human-readable information about acquired device
|
||||
/** ***********************************************************************************************
|
||||
* @brief psoc6_get_info Displays human-readable information about acquired device
|
||||
* @param bank current flash bank
|
||||
* @param buf pointer to buffer for human-readable text
|
||||
* @param buf_size size of the buffer
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
|
@ -494,8 +528,10 @@ static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Returns true if flash bank name represents Supervisory Flash
|
||||
/** ***********************************************************************************************
|
||||
* @brief Checks if given flash bank belongs to Supervisory Flash
|
||||
* @param bank current flash bank
|
||||
* @return true if flash bank belongs to Supervisory Flash
|
||||
*************************************************************************************************/
|
||||
static bool is_sflash_bank(struct flash_bank *bank)
|
||||
{
|
||||
|
@ -507,27 +543,33 @@ static bool is_sflash_bank(struct flash_bank *bank)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Returns true if flash bank name represents Work Flash
|
||||
/** ***********************************************************************************************
|
||||
* @brief Checks if given flash bank belongs to Work Flash
|
||||
* @param bank current flash bank
|
||||
* @return true if flash bank belongs to Work Flash
|
||||
*************************************************************************************************/
|
||||
static inline bool is_wflash_bank(struct flash_bank *bank)
|
||||
{
|
||||
return (bank->base == MEM_BASE_WFLASH);
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Returns true if flash bank name represents Main Flash
|
||||
/** ***********************************************************************************************
|
||||
* @brief Checks if given flash bank belongs to Main Flash
|
||||
* @param bank current flash bank
|
||||
* @return true if flash bank belongs to Main Flash
|
||||
*************************************************************************************************/
|
||||
static inline bool is_mflash_bank(struct flash_bank *bank)
|
||||
{
|
||||
return (bank->base == MEM_BASE_MFLASH);
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Probes the device and populates related data structures with target flash geometry data.
|
||||
/** ***********************************************************************************************
|
||||
* @brief Probes the device and populates related data structures with target flash geometry data.
|
||||
* This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a
|
||||
* running target.
|
||||
* Function assumes that size of Work Flash is 32kB (true for all current part numbers)
|
||||
* running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers)
|
||||
*
|
||||
* @param bank current flash bank
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_probe(struct flash_bank *bank)
|
||||
{
|
||||
|
@ -595,8 +637,10 @@ static int psoc6_probe(struct flash_bank *bank)
|
|||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Probes target device only if it hasn't been probed yet
|
||||
/** ***********************************************************************************************
|
||||
* @brief Probes target device only if it hasn't been probed yet
|
||||
* @param bank current flash bank
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
|
@ -611,8 +655,12 @@ static int psoc6_auto_probe(struct flash_bank *bank)
|
|||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Erases single sector (256k) on target device
|
||||
/** ***********************************************************************************************
|
||||
* @brief Erases single sector (256k) on target device
|
||||
* @param bank current flash bank
|
||||
* @param wa working area for SROM API parameters
|
||||
* @param addr starting address of the sector
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
|
||||
{
|
||||
|
@ -636,8 +684,12 @@ static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa,
|
|||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Erases single row (512b) on target device
|
||||
/** ***********************************************************************************************
|
||||
* @brief Erases single row (512b) on target device
|
||||
* @param bank current flash bank
|
||||
* @param wa working area for SROM API parameters
|
||||
* @param addr starting address of the flash row
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
|
||||
{
|
||||
|
@ -661,9 +713,14 @@ static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uin
|
|||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Performs Erase operation.
|
||||
* Function will try to use biggest erase block possible to speedup the operation
|
||||
/** ***********************************************************************************************
|
||||
* @brief Performs Erase operation. Function will try to use biggest erase block possible to
|
||||
* speedup the operation.
|
||||
*
|
||||
* @param bank current flash bank
|
||||
* @param first first sector to erase
|
||||
* @param last last sector to erase
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
|
@ -681,7 +738,7 @@ static int psoc6_erase(struct flash_bank *bank, int first, int last)
|
|||
|
||||
hr = sromalgo_prepare(target);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
goto exit;
|
||||
|
||||
hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
|
||||
if (hr != ERROR_OK)
|
||||
|
@ -720,9 +777,13 @@ exit:
|
|||
return hr;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* Programs single Flash Row
|
||||
/** ***********************************************************************************************
|
||||
* @brief Programs single Flash Row
|
||||
* @param bank current flash bank
|
||||
* @param addr address of the flash row
|
||||
* @param buffer pointer to the buffer with data
|
||||
* @param is_sflash true if current flash bank belongs to Supervisory Flash
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_program_row(struct flash_bank *bank,
|
||||
uint32_t addr,
|
||||
|
@ -773,9 +834,13 @@ exit:
|
|||
return hr;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
* Programs set of Rows
|
||||
/** ***********************************************************************************************
|
||||
* @brief Performs Program operation
|
||||
* @param bank current flash bank
|
||||
* @param buffer pointer to the buffer with data
|
||||
* @param offset starting offset in falsh bank
|
||||
* @param count number of bytes in buffer
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
static int psoc6_program(struct flash_bank *bank,
|
||||
const uint8_t *buffer,
|
||||
|
@ -787,11 +852,11 @@ static int psoc6_program(struct flash_bank *bank,
|
|||
const bool is_sflash = is_sflash_bank(bank);
|
||||
int hr;
|
||||
|
||||
uint8_t page_buf[psoc6_info->row_sz];
|
||||
|
||||
hr = sromalgo_prepare(target);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
|
||||
uint8_t page_buf[psoc6_info->row_sz];
|
||||
goto exit;
|
||||
|
||||
while (count) {
|
||||
uint32_t row_offset = offset % psoc6_info->row_sz;
|
||||
|
@ -804,7 +869,7 @@ static int psoc6_program(struct flash_bank *bank,
|
|||
hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash);
|
||||
if (hr != ERROR_OK) {
|
||||
LOG_ERROR("Failed to program Flash at address 0x%08X", aligned_addr);
|
||||
break;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
buffer += row_bytes;
|
||||
|
@ -812,13 +877,15 @@ static int psoc6_program(struct flash_bank *bank,
|
|||
count -= row_bytes;
|
||||
}
|
||||
|
||||
hr = sromalgo_release(target);
|
||||
exit:
|
||||
sromalgo_release(target);
|
||||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Performs Mass Erase of given flash bank
|
||||
* Syntax: psoc6 mass_erase bank_id
|
||||
/** ***********************************************************************************************
|
||||
* @brief Performs Mass Erase operation
|
||||
* @param bank flash bank index to erase
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
COMMAND_HANDLER(psoc6_handle_mass_erase_command)
|
||||
{
|
||||
|
@ -835,13 +902,16 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command)
|
|||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Simulates broken Vector Catch
|
||||
/** ***********************************************************************************************
|
||||
* @brief Simulates broken Vector Catch
|
||||
* Function will try to determine entry point of user application. If it succeeds it will set HW
|
||||
* breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
|
||||
* In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
|
||||
* reset CM4 anyway, so using SYSRESETREQ is safe here.
|
||||
* In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
|
||||
*
|
||||
* @param target current target
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
int handle_reset_halt(struct target *target)
|
||||
{
|
||||
|
@ -889,33 +959,42 @@ int handle_reset_halt(struct target *target)
|
|||
|
||||
const struct armv7m_common *cm = target_to_armv7m(target);
|
||||
|
||||
/* PSoC6 reboots immediatelly after issuing SYSRESETREQ / VECTRESET
|
||||
* this disables SWD/JTAG pins momentarily and may break communication
|
||||
* Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */
|
||||
if (is_cm0) {
|
||||
/* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
|
||||
LOG_INFO("psoc6.cm0: bkpt @0x%08X, issuing SYSRESETREQ", reset_addr);
|
||||
hr = mem_ap_write_atomic_u32(cm->debug_ap,
|
||||
NVIC_AIRCR,
|
||||
mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
|
||||
AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
|
||||
|
||||
/* Wait for bootcode and initialize DAP */
|
||||
usleep(3000);
|
||||
dap_dp_init(cm->debug_ap->dap);
|
||||
} else {
|
||||
LOG_INFO("psoc6.cm4: bkpt @0x%08X, issuing VECTRESET", reset_addr);
|
||||
hr = mem_ap_write_atomic_u32(cm->debug_ap,
|
||||
NVIC_AIRCR,
|
||||
mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR,
|
||||
AIRCR_VECTKEY | AIRCR_VECTRESET);
|
||||
if (hr != ERROR_OK)
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Wait 100ms for bootcode and reinitialize DAP */
|
||||
usleep(100000);
|
||||
dap_dp_init(cm->debug_ap->dap);
|
||||
|
||||
target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
|
||||
|
||||
/* Remove the break point */
|
||||
breakpoint_remove(target, reset_addr);
|
||||
|
||||
return hr;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/** ***********************************************************************************************
|
||||
* @brief Simulates broken Vector Catch
|
||||
* Function will try to determine entry point of user application. If it succeeds it will set HW
|
||||
* breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
|
||||
* In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
|
||||
* reset CM4 anyway, so using SYSRESETREQ is safe here.
|
||||
* In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
|
||||
*
|
||||
* @return ERROR_OK in case of success, ERROR_XXX code otherwise
|
||||
*************************************************************************************************/
|
||||
COMMAND_HANDLER(psoc6_handle_reset_halt)
|
||||
{
|
||||
if (CMD_ARGC)
|
||||
|
@ -945,7 +1024,7 @@ static const struct command_registration psoc6_exec_command_handlers[] = {
|
|||
.name = "mass_erase",
|
||||
.handler = psoc6_handle_mass_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = NULL,
|
||||
.usage = "bank",
|
||||
.help = "Erases entire Main Flash",
|
||||
},
|
||||
{
|
||||
|
|
|
@ -82,21 +82,32 @@ proc psoc6_deassert_post { target } {
|
|||
$target arp_examine
|
||||
|
||||
global RESET_MODE
|
||||
global TARGET
|
||||
|
||||
if { $RESET_MODE ne "run" } {
|
||||
$target arp_poll
|
||||
$target arp_poll
|
||||
set st [$target curstate]
|
||||
|
||||
if { $st eq "reset" } {
|
||||
# we assume running state follows
|
||||
# if reset accidentally halts, waiting is useless
|
||||
catch { $target arp_waitstate running 100 }
|
||||
set st [$target curstate]
|
||||
}
|
||||
|
||||
if { $st eq "running" } {
|
||||
echo "$target: Ran after reset and before halt..."
|
||||
if { $target eq "${TARGET}.cm0" } {
|
||||
# Try to cleanly reset whole system
|
||||
# and halt the CM0 at entry point
|
||||
psoc6 reset_halt
|
||||
$target arp_waitstate halted 100
|
||||
} else {
|
||||
$target arp_halt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { $_ENABLE_CM0 } {
|
||||
|
@ -133,3 +144,7 @@ if { $_ENABLE_CM0 } {
|
|||
# Use CM0+ by default on dual-core devices
|
||||
targets ${TARGET}.cm0
|
||||
}
|
||||
|
||||
if {[using_jtag]} {
|
||||
swj_newdap $_CHIPNAME bs -irlen 18 -expected-id 0x2e200069
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue