ec521

Dependencies:   mbed

FreescaleIAP/FreescaleIAP.cpp

Committer:
gaving
Date:
2018-04-22
Revision:
0:e2f78ce2a5cf

File content as of revision 0:e2f78ce2a5cf:

#include "FreescaleIAP.h"

//#define IAPDEBUG

#ifdef TARGET_K64F
//For K64F
#   include "MK64F12.h"
#   define USE_ProgramPhrase 1
#   define FTFA                        FTFE
#   define FTFA_FSTAT_FPVIOL_MASK      FTFE_FSTAT_FPVIOL_MASK 
#   define FTFA_FSTAT_ACCERR_MASK      FTFE_FSTAT_ACCERR_MASK
#   define FTFA_FSTAT_RDCOLERR_MASK    FTFE_FSTAT_RDCOLERR_MASK
#   define FTFA_FSTAT_CCIF_MASK        FTFE_FSTAT_CCIF_MASK
#   define FTFA_FSTAT_MGSTAT0_MASK     FTFE_FSTAT_MGSTAT0_MASK
#else
//Different names used on at least the K20:
#   ifndef FTFA_FSTAT_FPVIOL_MASK
#       define FTFA                        FTFL
#       define FTFA_FSTAT_FPVIOL_MASK      FTFL_FSTAT_FPVIOL_MASK 
#       define FTFA_FSTAT_ACCERR_MASK      FTFL_FSTAT_ACCERR_MASK
#       define FTFA_FSTAT_RDCOLERR_MASK    FTFL_FSTAT_RDCOLERR_MASK
#       define FTFA_FSTAT_CCIF_MASK        FTFL_FSTAT_CCIF_MASK
#       define FTFA_FSTAT_MGSTAT0_MASK     FTFL_FSTAT_MGSTAT0_MASK
#   endif
#endif


enum FCMD {
    Read1s = 0x01,
    ProgramCheck = 0x02,
    ReadResource = 0x03,
    ProgramLongword = 0x06,
    ProgramPhrase = 0x07,    
    EraseSector = 0x09,
    Read1sBlock = 0x40,
    ReadOnce = 0x41,
    ProgramOnce = 0x43,
    EraseAll = 0x44,
    VerifyBackdoor = 0x45
    };

inline void run_command(void);
bool check_boundary(int address, unsigned int length);
bool check_align(int address);
IAPCode verify_erased(int address, unsigned int length);
IAPCode check_error(void);
IAPCode program_word(int address, char *data);
    
__attribute__((section(".ARM.__at_0x11000"))) IAPCode erase_sector(int address) {
    #ifdef IAPDEBUG
    printf("IAP: Erasing at %x\r\n", address);
    #endif
    if (check_align(address))
        return AlignError;
    
    //Setup command
    FTFA->FCCOB0 = EraseSector;
    FTFA->FCCOB1 = (address >> 16) & 0xFF;
    FTFA->FCCOB2 = (address >> 8) & 0xFF;
    FTFA->FCCOB3 = address & 0xFF;
    
    run_command();
    
    return check_error();
}

__attribute__((section(".ARM.__at_0x11100"))) IAPCode program_flash(int address, char *data, unsigned int length) {
    #ifdef IAPDEBUG
    printf("IAP: Programming flash at %x with length %d\r\n", address, length);
    #endif
    if (check_align(address))
        return AlignError;
        
    IAPCode eraseCheck = verify_erased(address, length);
    if (eraseCheck != Success)
        return eraseCheck;
    
    IAPCode progResult;
#ifdef USE_ProgramPhrase
    for (int i = 0; i < length; i+=8) {
        progResult = program_word(address + i, data + i);
        if (progResult != Success)
            return progResult;
    }
#else
    for (int i = 0; i < length; i+=4) {
        progResult = program_word(address + i, data + i);
        if (progResult != Success)
            return progResult;
    }
#endif    
    return Success;
}

__attribute__((section(".ARM.__at_0x11300"))) uint32_t flash_size(void) {
    uint32_t retval = (SIM->FCFG2 & 0x7F000000u) >> (24-13);
    if (SIM->FCFG2 & (1<<23))           //Possible second flash bank
        retval += (SIM->FCFG2 & 0x007F0000u) >> (16-13);
    return retval;
}

__attribute__((section(".ARM.__at_0x11400"))) IAPCode program_word(int address, char *data) {
    #ifdef IAPDEBUG
    #ifdef USE_ProgramPhrase
    printf("IAP: Programming word at %x, %d - %d - %d - %d - %d - %d - %d - %d\r\n", address, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
    #else
    printf("IAP: Programming word at %x, %d - %d - %d - %d\r\n", address, data[0], data[1], data[2], data[3]);
    #endif
    
    #endif
    if (check_align(address))
        return AlignError;
#ifdef USE_ProgramPhrase
    FTFA->FCCOB0 = ProgramPhrase;
    FTFA->FCCOB1 = (address >> 16) & 0xFF;
    FTFA->FCCOB2 = (address >> 8) & 0xFF;
    FTFA->FCCOB3 = address & 0xFF;
    FTFA->FCCOB4 = data[3];
    FTFA->FCCOB5 = data[2];
    FTFA->FCCOB6 = data[1];
    FTFA->FCCOB7 = data[0];
    FTFA->FCCOB8 = data[7];
    FTFA->FCCOB9 = data[6];
    FTFA->FCCOBA = data[5];
    FTFA->FCCOBB = data[4];    
#else
    //Setup command
    FTFA->FCCOB0 = ProgramLongword;
    FTFA->FCCOB1 = (address >> 16) & 0xFF;
    FTFA->FCCOB2 = (address >> 8) & 0xFF;
    FTFA->FCCOB3 = address & 0xFF;
    FTFA->FCCOB4 = data[3];
    FTFA->FCCOB5 = data[2];
    FTFA->FCCOB6 = data[1];
    FTFA->FCCOB7 = data[0];
#endif    
    run_command();
    
    return check_error();
}

/* Clear possible flags which are set, run command, wait until done */
__attribute__((section(".ARM.__at_0x11500"))) inline void run_command(void) {
    //Clear possible old errors, start command, wait until done
    FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK;
    FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK;
    while (!(FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK));
}    
    
    

/* Check if no flash boundary is violated
   Returns true on violation */
__attribute__((section(".ARM.__at_0x11600"))) bool check_boundary(int address, unsigned int length) {
    int temp = (address+length - 1) / SECTOR_SIZE;
    address /= SECTOR_SIZE;
    bool retval = (address != temp);
    #ifdef IAPDEBUG
    if (retval)
        printf("IAP: Boundary violation\r\n");
    #endif
    return retval;
}

/* Check if address is correctly aligned
   Returns true on violation */
__attribute__((section(".ARM.__at_0x11700"))) bool check_align(int address) {
    bool retval = address & 0x03;
    #ifdef IAPDEBUG
    if (retval)
        printf("IAP: Alignment violation\r\n");
    #endif
    return retval;
}

/* Check if an area of flash memory is erased
   Returns error code or Success (in case of fully erased) */
__attribute__((section(".ARM.__at_0x11800"))) IAPCode verify_erased(int address, unsigned int length) {
    #ifdef IAPDEBUG
    printf("IAP: Verify erased at %x with length %d\r\n", address, length);
    #endif
    
    if (check_align(address))
        return AlignError;
    
    //Setup command
    FTFA->FCCOB0 = Read1s;
    FTFA->FCCOB1 = (address >> 16) & 0xFF;
    FTFA->FCCOB2 = (address >> 8) & 0xFF;
    FTFA->FCCOB3 = address & 0xFF;
    FTFA->FCCOB4 = (length >> 10) & 0xFF;
    FTFA->FCCOB5 = (length >> 2) & 0xFF;
    FTFA->FCCOB6 = 0;
    
    run_command();
    
    IAPCode retval = check_error();
    if (retval == RuntimeError) {
        #ifdef IAPDEBUG
        printf("IAP: Flash was not erased\r\n");
        #endif
        return EraseError;
    }
    return retval;
        
}

/* Check if an error occured 
   Returns error code or Success*/
__attribute__((section(".ARM.__at_0x11900"))) IAPCode check_error(void) {
    if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) {
        #ifdef IAPDEBUG
        printf("IAP: Protection violation\r\n");
        #endif
        return ProtectionError;
    }
    if (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) {
        #ifdef IAPDEBUG
        printf("IAP: Flash access error\r\n");
        #endif
        return AccessError;
    }
    if (FTFA->FSTAT & FTFA_FSTAT_RDCOLERR_MASK) {
        #ifdef IAPDEBUG
        printf("IAP: Collision error\r\n");
        #endif
        return CollisionError;
    }
    if (FTFA->FSTAT & FTFA_FSTAT_MGSTAT0_MASK) {
        #ifdef IAPDEBUG
        printf("IAP: Runtime error\r\n");
        #endif
        return RuntimeError;
    }
    #ifdef IAPDEBUG
    printf("IAP: No error reported\r\n");
    #endif
    return Success;
}