/*********************************************************************** * 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 #include #include #include #include #include #include #include #include #include #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. = 2 ^ Shift. Shift = // 12 => = 2 ^ 12 = 4096 bytes #define PAGE_SIZE_SHIFT \ (14) // Smallest amount of data that can be programmed. = 2 ^ // Shift. Shift = 3 => = 2^3 = 8 bytes #else #define SECTOR_SIZE_SHIFT \ (12) // Flashes with uniform sectors only. = 2 ^ Shift. Shift = // 12 => = 2 ^ 12 = 4096 bytes #define PAGE_SIZE_SHIFT \ (12) // Smallest amount of data that can be programmed. = 2 ^ // Shift. Shift = 3 => = 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 // segment. Non-static to make // sure linker can keep this // symbol. Dummy needed to // make sure that // 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 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 == * 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 * 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 ***************************/