rusefi-1/firmware/hw_layer/ports/kinetis/flash.c

206 lines
5.7 KiB
C

/**
*
* @file flash.c
* @brief Lower-level code for Kinetis related to internal flash memory
* @author andreika <prometheus.pcb@gmail.com>
*/
#include "global.h"
#if EFI_INTERNAL_FLASH
#include "flash.h"
#include "fsl_ftfx_flexnvm.h"
#include <string.h>
//#define KINETIS_FLASH_DEBUG
typedef uint32_t flashdata_t;
static bool wasInit = false;
static bool isLocked = true;
static bool isInitializing = false;
static flexnvm_config_t flashCfg;
static status_t initStatus = -1;
static status_t protectStatus = -1;
static status_t securityStatus = -1;
static uint8_t protectValue = 0;
static ftfx_security_state_t sstate;
static kinetis_clock_type_e savedClockType = KINETIS_DEFAULT_CLK;
#ifdef KINETIS_FLASH_DEBUG
void flashPrintStatus(void) {
debugLog("* flashInit status=%d\r\n", initStatus);
debugLog("* FLEXNVM_DflashGetProtection status=%d prot=%d\r\n", protectStatus, protectValue);
debugLog("* FLEXNVM_GetSecurityState status=%d security=0x%08x\r\n", securityStatus, sstate);
uint32_t dflashBlockBase = 0;
uint32_t dflashTotalSize = 0;
uint32_t dflashSectorSize = 0;
/* Get flash properties*/
FLEXNVM_GetProperty(&flashCfg, kFLEXNVM_PropertyDflashBlockBaseAddr, &dflashBlockBase);
FLEXNVM_GetProperty(&flashCfg, kFLEXNVM_PropertyDflashTotalSize, &dflashTotalSize);
FLEXNVM_GetProperty(&flashCfg, kFLEXNVM_PropertyDflashSectorSize, &dflashSectorSize);
debugLog("Data Flash Base Address: (0x%x)\r\n", dflashBlockBase);
debugLog("Data Flash Total Size:\t%d KB, Hex: (0x%x)\r\n", (dflashTotalSize / 1024), dflashTotalSize);
debugLog("Data Flash Sector Size:\t%d KB, Hex: (0x%x)\r\n", (dflashSectorSize / 1024), dflashSectorSize);
}
#endif /* KINETIS_FLASH_DEBUG */
// should be called only from flashUnlock()
static bool flashInit(void) {
isInitializing = true;
memset(&flashCfg, 0, sizeof(flashCfg));
initStatus = FLEXNVM_Init(&flashCfg);
protectStatus = FLEXNVM_DflashGetProtection(&flashCfg, &protectValue);
securityStatus = FLEXNVM_GetSecurityState(&flashCfg, &sstate);
wasInit = true;
isInitializing = false;
#ifdef KINETIS_FLASH_DEBUG
flashPrintStatus();
#endif /* KINETIS_FLASH_DEBUG */
return (initStatus == kStatus_FTFx_Success);
}
bool flashUnlock(void) {
// chSysUnconditionalLock();
// this is strictly non-reentrant function!
if (!isLocked) {
// chSysUnconditionalUnlock();
return false; // already unlocked
}
isLocked = false;
savedClockType = ke1xf_clock_get_current_type();
// flash commands won't work in HSRUN clock mode
// we set a lower frequency clock
ke1xf_clock_init(kinetis_clock_int_osc_run);
// before any flash access function, we should have called init() first (but not from init() itself)
if (!isInitializing && !wasInit) {
flashInit();
}
return true;
}
bool flashLock(void) {
// this is strictly non-reentrant function!
if (isLocked) {
return false; // already locked
}
// restore clock
ke1xf_clock_init(savedClockType);
isLocked = true;
// chSysUnconditionalUnlock();
return true;
}
static int alignToWord(int v) {
return (v + FSL_FEATURE_FLASH_FLEX_NVM_SECTOR_CMD_ADDRESS_ALIGMENT - 1) & ~(FSL_FEATURE_FLASH_FLEX_NVM_SECTOR_CMD_ADDRESS_ALIGMENT - 1);
}
int flashErase(flashaddr_t address, size_t size) {
if (!flashUnlock())
return FLASH_RETURN_NO_PERMISSION;
flashaddr_t sizeAligned = alignToWord(size);
status_t status = FLEXNVM_DflashErase(&flashCfg, address, sizeAligned, kFTFx_ApiEraseKey);
flashLock();
#ifdef KINETIS_FLASH_DEBUG
debugLog("* flashErase(addr=%08x siz=%d sizeAligned=%d)=%d\r\n", address, size, sizeAligned, status);
#endif /* KINETIS_FLASH_DEBUG */
if (status == kStatus_FTFx_Success)
return FLASH_RETURN_SUCCESS;
return -(int)status;
}
int flashWrite(flashaddr_t address, const char* buffer, size_t size) {
if (!flashUnlock())
return FLASH_RETURN_NO_PERMISSION;
//FLEXNVM_DflashSetProtection(&flashCfg, 0xff);
flashaddr_t sizeAligned = alignToWord(size);
status_t status = FLEXNVM_DflashProgram(&flashCfg, address, (uint8_t *)buffer, sizeAligned);
flashLock();
#ifdef KINETIS_FLASH_DEBUG
debugLog("* flashWrite(addr=%08x siz=%d sizeAligned=%d)=%d\r\n", address, size, sizeAligned, status);
#endif /* KINETIS_FLASH_DEBUG */
if (status == kStatus_FTFx_Success)
return FLASH_RETURN_SUCCESS;
return -(int)status;
}
bool flashIsErased(flashaddr_t address, size_t size) {
/* Check for default set bits in the flash memory
* For efficiency, compare flashdata_t values as much as possible,
* then, fallback to byte per byte comparison. */
while (size >= sizeof(flashdata_t)) {
if (*(volatile flashdata_t*) address != (flashdata_t) (-1)) // flashdata_t being unsigned, -1 is 0xFF..FF
return false;
address += sizeof(flashdata_t);
size -= sizeof(flashdata_t);
}
while (size > 0) {
if (*(char*) address != 0xFF)
return false;
++address;
--size;
}
return TRUE;
}
bool flashCompare(flashaddr_t address, const char* buffer, size_t size) {
#if 0
uint32_t failAddr = 0, failDat = 0;
status_t status = FLEXNVM_DflashVerifyProgram(&flashCfg, address, size, (const uint8_t *)buffer,
kFTFx_MarginValueUser, &failAddr, &failDat);
return (status == kStatus_FTFx_Success);
#endif
/* For efficiency, compare flashdata_t values as much as possible,
* then, fallback to byte per byte comparison. */
while (size >= sizeof(flashdata_t)) {
if (*(volatile flashdata_t*) address != *(flashdata_t*) buffer)
return FALSE;
address += sizeof(flashdata_t);
buffer += sizeof(flashdata_t);
size -= sizeof(flashdata_t);
}
while (size > 0) {
if (*(volatile char*) address != *buffer)
return FALSE;
++address;
++buffer;
--size;
}
return TRUE;
}
int flashRead(flashaddr_t address, char* buffer, size_t size) {
memcpy(buffer, (char*) address, size);
return FLASH_RETURN_SUCCESS;
}
#endif /* EFI_INTERNAL_FLASH */