1016 lines
33 KiB
C
1016 lines
33 KiB
C
/***********************************************************************
|
|
* SEGGER Microcontroller GmbH *
|
|
* The Embedded Experts *
|
|
************************************************************************
|
|
* *
|
|
* (c) SEGGER Microcontroller GmbH *
|
|
* All rights reserved *
|
|
* www.segger.com *
|
|
* *
|
|
************************************************************************
|
|
* *
|
|
************************************************************************
|
|
* *
|
|
* *
|
|
* Licensing terms *
|
|
* *
|
|
* Redistribution and use in source and binary forms, with or without *
|
|
* modification, are permitted provided that the following conditions *
|
|
* are met: *
|
|
* *
|
|
* 1. Redistributions of source code must retain the above copyright *
|
|
* notice, this list of conditions and the following disclaimer. *
|
|
* *
|
|
* 2. Redistributions in binary form must reproduce the above *
|
|
* copyright notice, this list of conditions and the following *
|
|
* disclaimer in the documentation and/or other materials provided *
|
|
* with the distribution. *
|
|
* *
|
|
* *
|
|
* THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY *
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE *
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, *
|
|
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY *
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH. *
|
|
* DAMAGE. *
|
|
* *
|
|
************************************************************************
|
|
|
|
-------------------------- END-OF-HEADER -----------------------------
|
|
|
|
File : FlashPrg.c
|
|
Purpose : Implementation of RAMCode template
|
|
*/
|
|
|
|
#include <debug.h>
|
|
#include <flash_wrapper.h>
|
|
#include <flashloader_fuse_bin.h>
|
|
#include <param.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sd_boot_img/sd_boot_img.h>
|
|
#include <bpt_v2.h>
|
|
|
|
#include "FlashOS.h"
|
|
#include "flashloader.h"
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Defines (configurable)
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
//
|
|
// Only compile in functions that make sense to keep RAMCode as small as
|
|
// possible
|
|
//
|
|
#define SUPPORT_NATIVE_VERIFY \
|
|
(0) // Non-memory mapped flashes only. Flash cannot be read memory-mapped
|
|
#define SUPPORT_NATIVE_READ_FUNCTION \
|
|
(1) // Non-memory mapped flashes only. Flash cannot be read memory-mapped
|
|
#define SUPPORT_ERASE_CHIP \
|
|
(1) // To potentially speed up production programming: Erases whole flash
|
|
// bank / chip with special command
|
|
#define SUPPORT_TURBO_MODE (0) // Currently available for Cortex-M only
|
|
#define SUPPORT_SEGGER_OPEN_ERASE \
|
|
(1) // Flashes with uniform sectors only. Speed up erase because 1 OFL call
|
|
// may erase multiple sectors
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Defines (fixed)
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
#if CONFIG_HYPERBUS_MODE
|
|
#define SECTOR_SIZE_SHIFT \
|
|
(18) // Flashes with uniform sectors only. <SectorSize> = 2 ^ Shift. Shift =
|
|
// 12 => <SectorSize> = 2 ^ 12 = 4096 bytes
|
|
#define PAGE_SIZE_SHIFT \
|
|
(14) // Smallest amount of data that can be programmed. <PageSize> = 2 ^
|
|
// Shift. Shift = 3 => <PageSize> = 2^3 = 8 bytes
|
|
#else
|
|
#define SECTOR_SIZE_SHIFT \
|
|
(12) // Flashes with uniform sectors only. <SectorSize> = 2 ^ Shift. Shift =
|
|
// 12 => <SectorSize> = 2 ^ 12 = 4096 bytes
|
|
#define PAGE_SIZE_SHIFT \
|
|
(12) // Smallest amount of data that can be programmed. <PageSize> = 2 ^
|
|
// Shift. Shift = 3 => <PageSize> = 2^3 = 8 bytes
|
|
#endif
|
|
|
|
extern void device_init(void);
|
|
|
|
flash_wrapper_t *jflash_wrapper;
|
|
static struct spi_nor *jflash_loader;
|
|
char flash_buf[1uL << PAGE_SIZE_SHIFT];
|
|
char msg_buf[100];
|
|
static uint32_t msfs_crc = 0;
|
|
static uint32_t matched_sfs_crc = 0;
|
|
|
|
static const char *err_info[] = {
|
|
[ERR_UNKNOWN] = "unkown error",
|
|
[ERR_FUSE_READ_FAIL] = "Read fuse fail",
|
|
[ERR_FUSE_WRITE_CMD_VERIFY_FAIL] = "Write fuse cmd crc verify fail",
|
|
[ERR_FUSE_WRITE_FAIL] = "Write fuse fail",
|
|
[ERR_FUSE_READBACK_VERIFY_FAIL] = "Write fuse readback verify fail",
|
|
[ERR_INIT_FAIL] = "Init fail",
|
|
[ERR_BLANKCHECK_FAIL] = "Blankcheck fail",
|
|
[ERR_ERASE_ADDRESS_UNALIGNED] = "Erase address unaligned",
|
|
[ERR_ERASE_FAIL] = "Erase fail",
|
|
[ERR_ERASECHIP_FAIL] = "EraseChip fail",
|
|
[ERR_PROGRAM_ADDRESS_UNALIGNED] = "Program length unaligned",
|
|
[ERR_PROGRAM_FAIL] = "Program fail",
|
|
[ERR_PROGRAM_HYPERFLASH_FUSE_FAIL] = "Program hyperflash fuse fail",
|
|
[ERR_READ_LENGTH_UNALIGNED] = "Read address unaligned",
|
|
[ERR_READ_FAIL] = "Read fail",
|
|
[ERR_VERIFY_FAIL] = "Verify fail",
|
|
[ERR_FL_FUSE_SIZE_CHECK_FAIL] = "fuse bin size check fail",
|
|
[ERR_FL_FUSE_LENGTH_CHECK_FAIL] = "fuse item length check fail",
|
|
[ERR_FL_FUSE_ACTION_TYPE_NOT_FIND] = "fuse action type not find",
|
|
[ERR_FL_FUSE_CRC_CHECK_FAIL] = "fuse crc check fail",
|
|
[ERR_FL_FUSE_ENC_INIT_FAIL] = "fuse encrypto init fail",
|
|
[ERR_FL_FUSE_ENC_FAIL] = "fuse encrypto fail",
|
|
[ERR_FL_FUSE_MALLOC_FAIL] = "fuse malloc fail",
|
|
[ERR_FL_FUSE_GEN_DATA_FAIL] = "fuse gen data fail",
|
|
[ERR_FL_FLASH_MSFS_FAIL] = "flash msfs error",
|
|
[ERR_FL_MSFS_VERIFY_FAIL] = "MSFS Verify fail",
|
|
};
|
|
|
|
void report_error(enum fl_err_code err)
|
|
{
|
|
if (err < ERR_UNKNOWN || err >= ERR_MAX) {
|
|
snprintf(msg_buf, sizeof(msg_buf), "%s", err_info[ERR_UNKNOWN]);
|
|
} else {
|
|
snprintf(msg_buf, sizeof(msg_buf), "%s", err_info[err]);
|
|
}
|
|
ssdk_printf(SSDK_ERR, "%s\r\n", msg_buf);
|
|
}
|
|
|
|
#define JFLASHLOADER_DEBUG_LEVEL SSDK_DEBUG
|
|
|
|
__SECTION(".data") static volatile int board_init_flag = 0;
|
|
|
|
void clean_bss(void)
|
|
{
|
|
#if __ICCARM__
|
|
extern void __iar_data_init3(void);
|
|
__iar_data_init3();
|
|
#else
|
|
extern volatile uint32_t __bss_start;
|
|
extern volatile uint32_t __bss_end;
|
|
volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
|
|
volatile unsigned int *end = (volatile unsigned int *)&__bss_end;
|
|
while (start <= end) {
|
|
*start++ = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if __SES_ARM
|
|
static void ses_heap_init(void)
|
|
{
|
|
__ASM volatile("ldr R0, = _heap_start \n"
|
|
"ldr R1, = _heap_end \n"
|
|
"subs R1, R1, R0 \n"
|
|
"bl __SEGGER_RTL_init_heap \n");
|
|
}
|
|
#endif
|
|
|
|
void jflash_board_init_once(void)
|
|
{
|
|
if (board_init_flag == 0) {
|
|
clean_bss();
|
|
#if __SES_ARM
|
|
/* initializes heap for SES library */
|
|
ses_heap_init();
|
|
#endif
|
|
device_init();
|
|
board_init();
|
|
board_init_flag = 1;
|
|
}
|
|
}
|
|
|
|
__USED static int32_t jflash_fuse_read(uint32_t index, uint32_t *value)
|
|
{
|
|
jflash_board_init_once();
|
|
|
|
int32_t ret = 0;
|
|
ssdk_printf(SSDK_NOTICE, "Read fuse index %d\r\n", index);
|
|
ret = fuse_read(index, value);
|
|
if (ret != 0) {
|
|
report_error(ERR_FUSE_READ_FAIL);
|
|
return ret;
|
|
}
|
|
ssdk_printf(SSDK_NOTICE, "Read fuse success, value 0x%08x\r\n", *value);
|
|
return 0;
|
|
}
|
|
|
|
__USED int32_t jflash_fuse_write(uint32_t index, uint32_t value, uint32_t crc)
|
|
{
|
|
jflash_board_init_once();
|
|
|
|
// crc verify
|
|
uint32_t crc_ret = 0;
|
|
int32_t ret = 0;
|
|
|
|
ssdk_printf(SSDK_NOTICE, "Write fuse index:%d, value:%08x, crc:0x%x\r\n",
|
|
index, value, crc);
|
|
|
|
crc_ret = flashloader_crc32((uint8_t *)&index, 4, 0x0);
|
|
crc_ret = flashloader_crc32((uint8_t *)&value, 4, crc_ret);
|
|
|
|
if (crc != crc_ret) {
|
|
report_error(ERR_FUSE_WRITE_CMD_VERIFY_FAIL);
|
|
return -1;
|
|
}
|
|
ret = fuse_write(index, value);
|
|
if (ret != 0) {
|
|
if (ret == FL_FUSE_READ_ERROR)
|
|
report_error(ERR_FUSE_READ_FAIL);
|
|
else if (ret == FL_FUSE_WRITE_ERROR)
|
|
report_error(ERR_FUSE_WRITE_FAIL);
|
|
else if (ret == FL_FUSE_READBACK_VERIFY_ERROR)
|
|
report_error(ERR_FUSE_READBACK_VERIFY_FAIL);
|
|
return ret;
|
|
}
|
|
|
|
ssdk_printf(SSDK_NOTICE, "Write fuse success\r\n");
|
|
return 0;
|
|
}
|
|
|
|
typedef struct {
|
|
int32_t (*pfFuseSense)(uint32_t index, uint32_t *data);
|
|
int32_t (*pfFuseProg)(uint32_t index, uint32_t value, uint32_t crc);
|
|
int32_t (*jflash_program_fuse_bin)(uint32_t nNumBytes,
|
|
const uint8_t *pSrcBuff);
|
|
} SEMIDRIVE_FUSE_API;
|
|
|
|
__USED __SECTION(".FUSECODE") const SEMIDRIVE_FUSE_API SEMIDRIVE_FUSE_Api = {
|
|
jflash_fuse_read, jflash_fuse_write, jflash_program_fuse_bin};
|
|
|
|
//
|
|
// Default definitions for optional functions if not compiled in
|
|
// Makes Api table code further down less ugly
|
|
//
|
|
#if (SUPPORT_ERASE_CHIP == 0)
|
|
#define EraseChip NULL
|
|
#endif
|
|
#if (SUPPORT_NATIVE_VERIFY == 0)
|
|
#define Verify NULL
|
|
#endif
|
|
#if (SUPPORT_NATIVE_READ_FUNCTION == 0)
|
|
#define SEGGER_OPEN_Read NULL
|
|
#endif
|
|
#if (SUPPORT_SEGGER_OPEN_ERASE == 0)
|
|
#define SEGGER_OPEN_Erase NULL
|
|
#endif
|
|
#if (SUPPORT_TURBO_MODE == 0)
|
|
#define SEGGER_OPEN_Start NULL
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Types
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
typedef struct {
|
|
U32 AddVariablesHere;
|
|
} RESTORE_INFO;
|
|
|
|
static void _FeedWatchdog(void);
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Static data
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
// static RESTORE_INFO _RestoreInfo;
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Public data
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
__USED __SECTION(
|
|
".PRGDATA") volatile int PRGDATA_StartMarker; // Mark start of <PrgData>
|
|
// segment. Non-static to make
|
|
// sure linker can keep this
|
|
// symbol. Dummy needed to
|
|
// make sure that <PrgData>
|
|
// section in resulting ELF
|
|
// file is present. Needed by
|
|
// open flash loader logic on
|
|
// PC side
|
|
|
|
__USED __SECTION(".PRGCODE") const SEGGER_OFL_API
|
|
SEGGER_OFL_Api = { // Mark start of <PrgCode> segment. Non-static to
|
|
// make sure linker can keep this symbol.
|
|
_FeedWatchdog,
|
|
Init,
|
|
UnInit,
|
|
EraseSector,
|
|
ProgramPage,
|
|
BlankCheck,
|
|
EraseChip,
|
|
Verify,
|
|
SEGGER_OPEN_CalcCRC,
|
|
SEGGER_OPEN_Read,
|
|
SEGGER_OPEN_Program,
|
|
SEGGER_OPEN_Erase,
|
|
SEGGER_OPEN_Start};
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Static code
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
/*********************************************************************
|
|
*
|
|
* _FeedWatchdog
|
|
*
|
|
* Function description
|
|
* Feeds the watchdog. Needs to be called during RAMCode execution in case of
|
|
* an watchdog is active. In case no handling is necessary, it could perform a
|
|
* dummy access, to make sure that this function is linked in
|
|
*/
|
|
static void _FeedWatchdog(void)
|
|
{
|
|
*((volatile int *)&PRGDATA_StartMarker); // Dummy operation
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Public code
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Init
|
|
*
|
|
* Function description
|
|
* Handles the initialization of the flash module.
|
|
* It is called once per flash programming step (Erase, Program, Verify)
|
|
*
|
|
* Parameters
|
|
* Addr: Flash base address
|
|
* Freq: Clock frequency in Hz
|
|
* Func: Specifies the action followed by Init() (e.g.: 1 - Erase, 2 -
|
|
* Program, 3 - Verify / Read)
|
|
*
|
|
* Return value
|
|
* == 0 O.K.
|
|
* == 1 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is mandatory.
|
|
* (2) Use "noinline" attribute to make sure that function is never inlined
|
|
* and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
|
|
__SECTION(".data") static volatile int flashloader_init_flag = 0;
|
|
|
|
int Init(U32 Addr, U32 Freq, U32 Func)
|
|
{
|
|
(void)Addr;
|
|
(void)Freq;
|
|
(void)Func;
|
|
|
|
// Do not print here, otherwise an error occurs, UART has not been
|
|
// initialized
|
|
|
|
jflash_board_init_once();
|
|
|
|
if (flashloader_init_flag == 0) {
|
|
board_norflash_init();
|
|
flashloader_init(&jflash_loader);
|
|
read_back_buffer_flag = 0;
|
|
jflash_wrapper = flash_wrapper_init(jflash_loader);
|
|
if (jflash_wrapper == NULL) {
|
|
report_error(ERR_INIT_FAIL);
|
|
return 1;
|
|
}
|
|
flashloader_init_flag = 1;
|
|
}
|
|
|
|
ssdk_printf(SSDK_NOTICE, "Init Addr:0x%x, Func:0x%x\r\n", Addr, Func);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* UnInit
|
|
*
|
|
* Function description
|
|
* Handles the de-initialization of the flash module.
|
|
* It is called once per flash programming step (Erase, Program, Verify)
|
|
*
|
|
* Parameters
|
|
* Func Caller type (e.g.: 1 - Erase, 2 - Program, 3 - Verify)
|
|
*
|
|
* Return value
|
|
* == 0 O.K.
|
|
* == 1 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is mandatory.
|
|
* (2) Use "noinline" attribute to make sure that function is never inlined
|
|
* and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
int UnInit(U32 Func)
|
|
{
|
|
(void)Func;
|
|
//
|
|
// Uninit code
|
|
//
|
|
ssdk_printf(SSDK_NOTICE, "UnInit Func:0x%x\r\n", Func);
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* EraseSector
|
|
*
|
|
* Function description
|
|
* Erases one flash sector.
|
|
*
|
|
* Parameters
|
|
* SectorAddr Absolute address of the sector to be erased
|
|
*
|
|
* Return value
|
|
* == 0 O.K.
|
|
* == 1 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is mandatory.
|
|
* (2) Use "noinline" attribute to make sure that function is never inlined
|
|
* and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
int EraseSector(U32 SectorAddr)
|
|
{
|
|
ssdk_printf(JFLASHLOADER_DEBUG_LEVEL, "EraseSector SectorAddr:0x%x\r\n",
|
|
(uint32_t)SectorAddr);
|
|
int ret;
|
|
flash_addr_t addr = FLASH_ADDR_MASK(SectorAddr);
|
|
ret = flash_wrapper_erase(jflash_wrapper, addr,
|
|
(flash_size_t)jflash_wrapper->sector_size);
|
|
if (ret < 0) {
|
|
if (ret == FL_DL_ERASE_ADDRESS_UNALIGNED_ERROR)
|
|
report_error(ERR_ERASE_ADDRESS_UNALIGNED);
|
|
else
|
|
report_error(ERR_ERASE_FAIL);
|
|
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* ProgramPage
|
|
*
|
|
* Function description
|
|
* Programs one flash page.
|
|
*
|
|
* Parameters
|
|
* DestAddr Address to start programming on
|
|
* NumBytes Number of bytes to program. Guaranteed to be ==
|
|
* <FlashDevice.PageSize> pSrcBuff Pointer to data to be programmed
|
|
*
|
|
* Return value
|
|
* == 0 O.K.
|
|
* == 1 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is mandatory.
|
|
* (2) Use "noinline" attribute to make sure that function is never inlined
|
|
* and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
__SECTION(".data") static volatile int program_hyperflash_fuse_flag = 0;
|
|
|
|
int ProgramPage(U32 DestAddr, U32 NumBytes, U8 *pSrcBuff)
|
|
{
|
|
ssdk_printf(JFLASHLOADER_DEBUG_LEVEL,
|
|
"ProgramPage DestAddr:0x%x, "
|
|
"NumBytes:0x%x, pSrcBuff:0x%x\r\n",
|
|
(uint32_t)DestAddr, NumBytes, pSrcBuff);
|
|
|
|
int ret;
|
|
flash_addr_t addr = FLASH_ADDR_MASK(DestAddr);
|
|
|
|
if((0 == addr) && is_msfs_data(pSrcBuff)) {
|
|
msfs_crc = flashloader_crc32((uint8_t *)pSrcBuff, NumBytes, 0);
|
|
if(0 != get_matched_sfs(&(jflash_loader->info.flash_id[0]), (void **)&pSrcBuff, (uint32_t *)&NumBytes)) {
|
|
report_error(ERR_FL_FLASH_MSFS_FAIL);
|
|
return 1;
|
|
}
|
|
matched_sfs_crc = flashloader_crc32((uint8_t *)pSrcBuff, NumBytes, 0);
|
|
}
|
|
|
|
ret = flash_wrapper_write(jflash_wrapper, addr, (const uint8_t *)pSrcBuff,
|
|
(flash_size_t)NumBytes);
|
|
if (ret < 0) {
|
|
if (ret == FL_DL_PROGRAM_ADDRESS_UNALIGNED_ERROR)
|
|
report_error(ERR_PROGRAM_ADDRESS_UNALIGNED);
|
|
else
|
|
report_error(ERR_PROGRAM_FAIL);
|
|
return 1;
|
|
}
|
|
|
|
#if (CONFIG_HYPERBUS_MODE == 1) && (CONFIG_SDFACTORYTOOL_HYPERFLASH_FUSE == 1)
|
|
if (program_hyperflash_fuse_flag == 0) {
|
|
ret = program_hyperflash_fuse();
|
|
if (ret != 0) {
|
|
report_error(ERR_PROGRAM_HYPERFLASH_FUSE_FAIL);
|
|
return 1;
|
|
}
|
|
ssdk_printf(JFLASHLOADER_DEBUG_LEVEL,
|
|
"program hyperflash fuse done\r\n");
|
|
program_hyperflash_fuse_flag = 1;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* BlankCheck
|
|
*
|
|
* Function description
|
|
* Checks if a memory region is blank
|
|
*
|
|
* Parameters
|
|
* Addr Address to start checking
|
|
* NumBytes Number of bytes to be checked
|
|
* BlankData Blank (erased) value of flash (Most flashes have 0xFF, some
|
|
* have 0x00, some do not have a defined erased value)
|
|
*
|
|
* Return value
|
|
* == 0 O.K., blank
|
|
* == 1 O.K., *not* blank
|
|
* < 0 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is optional. If not present, the J-Link software will
|
|
* assume that erased state of a sector can be determined via normal
|
|
* memory-mapped readback of sector. (2) Use "noinline" attribute to make sure
|
|
* that function is never inlined and label not accidentally removed by linker
|
|
* from ELF file.
|
|
*/
|
|
int BlankCheck(U32 Addr, U32 NumBytes, U8 BlankData)
|
|
{
|
|
U32 ByteNumOfPage, NumCheck, NumCheck_tmp;
|
|
int ret;
|
|
flash_addr_t addr = FLASH_ADDR_MASK(Addr);
|
|
|
|
ssdk_printf(SSDK_NOTICE,
|
|
"BlankCheck Addr:0x%x, "
|
|
"NumBytes:0x%x, BlankData:0x%x\r\n",
|
|
(uint32_t)Addr, NumBytes, BlankData);
|
|
|
|
if (!IS_ALIGNED(addr, 4)) {
|
|
ssdk_printf(SSDK_NOTICE, "BlankCheck Addr unaligned:0x%x\r\n",
|
|
(uint32_t)Addr);
|
|
return -1;
|
|
}
|
|
|
|
ByteNumOfPage = (1uL << PAGE_SIZE_SHIFT);
|
|
|
|
do {
|
|
NumCheck = (NumBytes >= ByteNumOfPage) ? ByteNumOfPage : NumBytes;
|
|
NumCheck_tmp = NumCheck;
|
|
volatile U8 *pDestBuff = (U8 *)flash_buf;
|
|
ret = flash_wrapper_read(jflash_wrapper, addr, (uint8_t *)pDestBuff,
|
|
(flash_size_t)NumCheck_tmp);
|
|
if (ret < 0) {
|
|
report_error(ERR_BLANKCHECK_FAIL);
|
|
return -1;
|
|
}
|
|
|
|
do {
|
|
if (*pDestBuff++ != BlankData) {
|
|
return 1;
|
|
}
|
|
} while (--NumCheck_tmp);
|
|
|
|
addr += NumCheck;
|
|
NumBytes -= NumCheck;
|
|
|
|
} while (NumBytes);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* SEGGER_OPEN_CalcCRC
|
|
*
|
|
* Function description
|
|
* Calculates the CRC over a specified number of bytes
|
|
* Even more optimized version of Verify() as this avoids downloading the
|
|
* compare data into the RAMCode for comparison. Heavily reduces traffic between
|
|
* J-Link software and target and therefore speeds up verification process
|
|
* significantly.
|
|
*
|
|
* Parameters
|
|
* CRC CRC start value
|
|
* Addr Address where to start calculating CRC from
|
|
* NumBytes Number of bytes to calculate CRC on
|
|
* Polynom Polynom to be used for CRC calculation
|
|
*
|
|
* Return value
|
|
* CRC
|
|
*
|
|
* Notes
|
|
* (1) This function is optional
|
|
* (2) Use "noinline" attribute to make sure that function is never inlined
|
|
* and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
U32 SEGGER_OPEN_CalcCRC(U32 CRC, U32 Addr, U32 NumBytes, U32 Polynom)
|
|
{
|
|
ssdk_printf(SSDK_NOTICE,
|
|
"CalcCRC CRC:0x%x, "
|
|
"Addr:0x%x, NumBytes:0x%x, Polynom:0x%x\r\n",
|
|
CRC, (uint32_t)Addr, NumBytes, Polynom);
|
|
|
|
U32 ByteNumOfPage, NumCalcCRC;
|
|
uint32_t crc_ret = CRC;
|
|
int ret;
|
|
|
|
flash_addr_t addr = FLASH_ADDR_MASK(Addr);
|
|
ByteNumOfPage = (1uL << PAGE_SIZE_SHIFT);
|
|
|
|
/* msfs mode */
|
|
if((0 == addr) && (msfs_crc != 0) && (NumBytes < ByteNumOfPage)) {
|
|
/* sfs internal crc check */
|
|
if(0 != read_sfs(jflash_wrapper)) {
|
|
ssdk_printf(SSDK_ALERT, "sfs internal crc check error\r\n");
|
|
report_error(ERR_FL_MSFS_VERIFY_FAIL);
|
|
return -1;
|
|
}
|
|
|
|
/* check sfs is from msfs data */
|
|
ret = flash_wrapper_read(jflash_wrapper, FL_SFS_BASE, (uint8_t *)flash_buf,
|
|
(flash_size_t)FL_SFS_SIZE);
|
|
if (ret < 0) {
|
|
ssdk_printf(SSDK_ALERT, "read back sfs error\r\n");
|
|
report_error(ERR_FL_MSFS_VERIFY_FAIL);
|
|
return -1;
|
|
}
|
|
|
|
if(matched_sfs_crc != flashloader_crc32((uint8_t *)flash_buf, FL_SFS_SIZE, 0)) {
|
|
ssdk_printf(SSDK_ALERT, "check sfs is from msfs data error\r\n");
|
|
report_error(ERR_FL_MSFS_VERIFY_FAIL);
|
|
return -1;
|
|
}
|
|
|
|
ssdk_printf(SSDK_ALERT, "msfs check ok\r\n");
|
|
crc_ret = msfs_crc;
|
|
msfs_crc = 0;
|
|
return crc_ret;
|
|
}
|
|
|
|
/* normal mode */
|
|
do {
|
|
NumCalcCRC = (NumBytes >= ByteNumOfPage) ? ByteNumOfPage : NumBytes;
|
|
volatile U8 *pDestBuff = (U8 *)flash_buf;
|
|
ret = flash_wrapper_read(jflash_wrapper, addr, (uint8_t *)pDestBuff,
|
|
(flash_size_t)NumCalcCRC);
|
|
if (ret < 0) {
|
|
report_error(ERR_VERIFY_FAIL);
|
|
return -1;
|
|
}
|
|
|
|
crc_ret = flashloader_crc32((uint8_t *)pDestBuff, NumCalcCRC, crc_ret);
|
|
|
|
addr += NumCalcCRC;
|
|
NumBytes -= NumCalcCRC;
|
|
} while (NumBytes);
|
|
|
|
return crc_ret;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* SEGGER_OPEN_Program
|
|
*
|
|
* Function description
|
|
* Optimized variant of ProgramPage() which allows multiple pages to be
|
|
* programmed in 1 RAMCode call.
|
|
*
|
|
* Parameters
|
|
* DestAddr Address to start flash programming at.
|
|
* NumBytes Number of bytes to be program. Guaranteed to be multiple of
|
|
* <FlashDevice.PageSize> pSrcBuff Pointer to data to be programmed
|
|
*
|
|
* Return value
|
|
* == 0 O.K.
|
|
* == 1 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is optional. If not present, the J-Link software will
|
|
* use ProgramPage() (2) Use "noinline" attribute to make sure that function is
|
|
* never inlined and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
int SEGGER_OPEN_Program(U32 DestAddr, U32 NumBytes, U8 *pSrcBuff)
|
|
{
|
|
U32 ByteNumOfSector, NumProgram;
|
|
int ret;
|
|
flash_addr_t addr = FLASH_ADDR_MASK(DestAddr);
|
|
|
|
ssdk_printf(SSDK_NOTICE,
|
|
"Program DestAddr:0x%x, "
|
|
"NumBytes:0x%x, pSrcBuff:0x%x\r\n",
|
|
(uint32_t)DestAddr, NumBytes, pSrcBuff);
|
|
|
|
ByteNumOfSector = jflash_wrapper->sector_size;
|
|
|
|
if((0 == addr) && is_msfs_data(pSrcBuff)) {
|
|
msfs_crc = flashloader_crc32((uint8_t *)pSrcBuff, NumBytes, 0);
|
|
if(0 != get_matched_sfs(&(jflash_loader->info.flash_id[0]), (void **)&pSrcBuff, (uint32_t *)&NumBytes)) {
|
|
report_error(ERR_FL_FLASH_MSFS_FAIL);
|
|
return 1;
|
|
}
|
|
matched_sfs_crc = flashloader_crc32((uint8_t *)pSrcBuff, NumBytes, 0);
|
|
}
|
|
|
|
do {
|
|
NumProgram = (NumBytes >= ByteNumOfSector) ? ByteNumOfSector : NumBytes;
|
|
|
|
ret =
|
|
flash_wrapper_write(jflash_wrapper, addr, (const uint8_t *)pSrcBuff,
|
|
(flash_size_t)NumProgram);
|
|
if (ret < 0) {
|
|
if (ret == FL_DL_PROGRAM_ADDRESS_UNALIGNED_ERROR)
|
|
report_error(ERR_PROGRAM_ADDRESS_UNALIGNED);
|
|
else
|
|
report_error(ERR_PROGRAM_FAIL);
|
|
return 1;
|
|
}
|
|
pSrcBuff += NumProgram;
|
|
addr += NumProgram;
|
|
NumBytes -= NumProgram;
|
|
} while (NumBytes);
|
|
|
|
#if (CONFIG_HYPERBUS_MODE == 1) && (CONFIG_SDFACTORYTOOL_HYPERFLASH_FUSE == 1)
|
|
if (program_hyperflash_fuse_flag == 0) {
|
|
ret = program_hyperflash_fuse();
|
|
if (ret != 0) {
|
|
report_error(ERR_PROGRAM_HYPERFLASH_FUSE_FAIL);
|
|
return 1;
|
|
}
|
|
ssdk_printf(JFLASHLOADER_DEBUG_LEVEL,
|
|
"program hyperflash fuse done\r\n");
|
|
program_hyperflash_fuse_flag = 1;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Verify
|
|
*
|
|
* Function description
|
|
* Verifies flash contents.
|
|
* Usually not compiled in. Only needed for non-memory mapped flashes.
|
|
*
|
|
* Parameters
|
|
* Addr Address to start verify on
|
|
* NumBytes Number of bytes to verify
|
|
* pBuff Pointer data to compare flash contents to
|
|
*
|
|
* Return value
|
|
* == (Addr + NumBytes): O.K.
|
|
* != (Addr + NumBytes): *not* O.K. (ideally the fail address is returned)
|
|
*
|
|
* Notes
|
|
* (1) This function is optional. If not present, the J-Link software will
|
|
* assume that flash memory can be verified via memory-mapped readback of flash
|
|
* contents. (2) Use "noinline" attribute to make sure that function is never
|
|
* inlined and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
#if SUPPORT_NATIVE_VERIFY
|
|
U32 Verify(U32 Addr, U32 NumBytes, U8 *pBuff)
|
|
{
|
|
unsigned char *pFlash;
|
|
unsigned long r;
|
|
U32 ByteNumOfPage, NumVerify, NumVerify_tmp;
|
|
int ret;
|
|
flash_addr_t addr = FLASH_ADDR_MASK(Addr);
|
|
|
|
ssdk_printf(JFLASHLOADER_DEBUG_LEVEL,
|
|
"Verify Addr:0x%x, "
|
|
"NumBytes:0x%x, pBuff:0x%x\r\n",
|
|
(uint32_t)Addr, NumBytes, pBuff);
|
|
|
|
ByteNumOfPage = (1uL << PAGE_SIZE_SHIFT);
|
|
r = Addr;
|
|
|
|
do {
|
|
NumVerify = (NumBytes >= ByteNumOfPage) ? ByteNumOfPage : NumBytes;
|
|
NumVerify_tmp = NumVerify;
|
|
pFlash = (U8 *)flash_buf;
|
|
ret = flash_wrapper_read(jflash_wrapper, addr, (uint8_t *)pFlash,
|
|
(flash_size_t)NumVerify_tmp);
|
|
if (ret < 0) {
|
|
if (ret == FL_DL_READ_LENGTH_UNALIGNED_ERROR)
|
|
report_error(ERR_READ_LENGTH_UNALIGNED);
|
|
else
|
|
report_error(ERR_READ_FAIL);
|
|
return -1;
|
|
}
|
|
|
|
do {
|
|
if (*pFlash != *pBuff) {
|
|
r = (unsigned long)pFlash;
|
|
return r;
|
|
}
|
|
pFlash++;
|
|
pBuff++;
|
|
} while (--NumVerify_tmp);
|
|
|
|
r += NumVerify;
|
|
addr += NumVerify;
|
|
NumBytes -= NumVerify;
|
|
|
|
} while (NumBytes);
|
|
|
|
return r;
|
|
}
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* EraseChip
|
|
*
|
|
* Function description
|
|
* Erases the entire flash.
|
|
*
|
|
* Return value
|
|
* == 0 O.K.
|
|
* == 1 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is optional. If not present, J-Link will always use
|
|
* EraseSector() for erasing. (2) Use "noinline" attribute to make sure that
|
|
* function is never inlined and label not accidentally removed by linker from
|
|
* ELF file.
|
|
*/
|
|
#if SUPPORT_ERASE_CHIP
|
|
int EraseChip(void)
|
|
{
|
|
ssdk_printf(SSDK_NOTICE, "EraseChip\r\n");
|
|
int ret;
|
|
ret = flash_wrapper_erase(jflash_wrapper, 0,
|
|
(flash_size_t)jflash_wrapper->flash_size);
|
|
if (ret < 0) {
|
|
report_error(ERR_ERASECHIP_FAIL);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* SEGGER_OPEN_Read
|
|
*
|
|
* Function description
|
|
* Reads a specified number of bytes from flash into the provided buffer.
|
|
* Usually not compiled in. Only needed for non-memory mapped flashes.
|
|
*
|
|
* Parameters
|
|
* Addr Address to start reading from
|
|
* NumBytes Number of bytes to read
|
|
* pDestBuff Pointer to buffer to store read data
|
|
*
|
|
* Return value
|
|
* >= 0: O.K., NumBytes read
|
|
* < 0: Error
|
|
*
|
|
* Notes
|
|
* (1) This function is optional. If not present, the J-Link software will
|
|
* assume that a normal memory-mapped read can be performed to read from flash.
|
|
* (2) Use "noinline" attribute to make sure that function is never inlined
|
|
* and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
#if SUPPORT_NATIVE_READ_FUNCTION
|
|
int SEGGER_OPEN_Read(U32 Addr, U32 NumBytes, U8 *pDestBuff)
|
|
{
|
|
int ret;
|
|
flash_addr_t addr = FLASH_ADDR_MASK(Addr);
|
|
|
|
ssdk_printf(SSDK_NOTICE,
|
|
"Read Addr:0x%x, "
|
|
"NumBytes:0x%x, pDestBuff:0x%x\r\n",
|
|
(uint32_t)Addr, NumBytes, pDestBuff);
|
|
|
|
ret = flash_wrapper_read(jflash_wrapper, addr, (uint8_t *)pDestBuff,
|
|
(flash_size_t)NumBytes);
|
|
if (ret < 0) {
|
|
if (ret == FL_DL_READ_LENGTH_UNALIGNED_ERROR)
|
|
report_error(ERR_READ_LENGTH_UNALIGNED);
|
|
else
|
|
report_error(ERR_READ_FAIL);
|
|
return -1;
|
|
}
|
|
_FeedWatchdog();
|
|
return NumBytes;
|
|
}
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* SEGGER_OPEN_Erase
|
|
*
|
|
* Function description
|
|
* Erases one or more flash sectors.
|
|
* The implementation from this template only works on flashes that have
|
|
* uniform sectors.
|
|
*
|
|
* Notes
|
|
* (1) This function can rely on that at least one sector will be passed
|
|
* (2) This function must be able to handle multiple sectors at once
|
|
* (3) This function can rely on that only multiple sectors of the same
|
|
* sector size will be passed. (e.g. if the device has two sectors with
|
|
* different sizes, the DLL will call this function two times with NumSectors =
|
|
* 1)
|
|
*
|
|
* Parameters
|
|
* SectorAddr: Address of the start sector to be erased
|
|
* SectorIndex: Index of the start sector to be erased (1st sector handled by
|
|
* this flash bank: SectorIndex == 0) NumSectors: Number of sectors to be
|
|
* erased. Min. 1
|
|
*
|
|
* Return value
|
|
* == 0 O.K.
|
|
* == 1 Error
|
|
*
|
|
* Notes
|
|
* (1) This function is optional. If not present, the J-Link software will
|
|
* use EraseSector() (2) Use "noinline" attribute to make sure that function is
|
|
* never inlined and label not accidentally removed by linker from ELF file.
|
|
*/
|
|
#if SUPPORT_SEGGER_OPEN_ERASE
|
|
int SEGGER_OPEN_Erase(U32 SectorAddr, U32 SectorIndex, U32 NumSectors)
|
|
{
|
|
int r;
|
|
|
|
ssdk_printf(SSDK_NOTICE,
|
|
"Erase SectorAddr:0x%x, "
|
|
"SectorIndex:0x%x, NumSectors:0x%x\r\n",
|
|
(uint32_t)SectorAddr, SectorIndex, NumSectors);
|
|
|
|
(void)SectorIndex;
|
|
_FeedWatchdog();
|
|
r = 0;
|
|
do {
|
|
r = EraseSector(SectorAddr);
|
|
if (r) {
|
|
break;
|
|
}
|
|
SectorAddr += (1 << SECTOR_SIZE_SHIFT);
|
|
} while (--NumSectors);
|
|
return r;
|
|
}
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
*
|
|
* SEGGER_OPEN_Start
|
|
*
|
|
* Function description
|
|
* Starts the turbo mode of flash algo.
|
|
* Currently only available for Cortex-M based targets.
|
|
*/
|
|
#if SUPPORT_TURBO_MODE
|
|
void SEGGER_OPEN_Start(volatile struct SEGGER_OPEN_CMD_INFO *pInfo)
|
|
{
|
|
SEGGER_OFL_Lib_StartTurbo(&SEGGER_OFL_Api, pInfo);
|
|
}
|
|
#endif
|
|
|
|
/**************************** End of file ***************************/
|