/*
 * internal_flash.c
 *
 *  Created on: 9 нояб. 2023 г.
 *      Author: seklyuts
 */
#include "f28x_project.h"
#include "hw_memmap.h"

#include "flash.h"
#include "device.h"

//
// Included Files
//
#include "driverlib.h"


//
// Include Flash API include file
//
#include "F021_F2838x_C28x.h"

// Include Flash API example header file
//
#include "flash_programming_f2838x_c28x.h"
#include "internal_flash.h"




#define  WORDS_IN_FLASH_BUFFER    2048
#define DEVICE_OSCSRC_FREQ          25000000U
#define DEVICE_SYSCLK_FREQ          ((DEVICE_OSCSRC_FREQ * 32) / (2 * 2 * 1))
//#pragma  DATA_SECTION(Buffer,"DataBufferSection");

//uint16_t   Buffer[WORDS_IN_FLASH_BUFFER];

//uint32_t   *Buffer32 = (uint32 *)Buffer;

#pragma  DATA_SECTION(Buffer,"MSGRAM_CM_TO_CPU");

uint16_t   Buffer[WORDS_IN_FLASH_BUFFER];

uint32_t   *Buffer32 = (uint32_t *)CMTOCPUXMSGRAM0_BASE;

//
// Prototype of the functions used in this example
//

uint32_t FlashBankStartAddr[14] = {Bzero_Sector0_start, Bzero_Sector1_start, Bzero_Sector2_start, Bzero_Sector3_start, Bzero_Sector4_start, Bzero_Sector5_start, Bzero_Sector6_start, Bzero_Sector7_start,
                     Bzero_Sector8_start, Bzero_Sector9_start, Bzero_Sector10_start, Bzero_Sector11_start, Bzero_Sector12_start, Bzero_Sector13_start};


uint16_t Sector_length[14] = {Sector16KB_u32length, Sector16KB_u32length, Sector16KB_u32length, Sector16KB_u32length, Sector64KB_u32length, Sector64KB_u32length, Sector64KB_u32length,
                              Sector64KB_u32length, Sector64KB_u32length, Sector64KB_u32length, Sector64KB_u32length, Sector16KB_u32length, Sector16KB_u32length, Sector16KB_u32length};


uint32_t internal_flash_FlashBankStartAddr(uint16_t bank)
{
    return FlashBankStartAddr[bank];
}


uint16_t Internal_flash_Sektor_Addr(uint32_t Addr_start)
{
    Fapi_FlashBankType sektor;
    for (sektor=Fapi_FlashBank0; sektor < Fapi_FlashBank13; sektor++ )
    {
        if(Addr_start < (FlashBankStartAddr[sektor+1])) return sektor;
    }
    return Fapi_FlashBank13;
}

void Internal_flash_Init(void)
{
    Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, 3);
#ifdef CPU1
    EALLOW;
    //MemCfg_setGSRAMMasterSel(MEMCFG_SECT_GS0, MEMCFG_GSRAMMASTER_CPU2);
    HWREG(MEMCFG_BASE + MEMCFG_O_GSXMSEL) |= MEMCFG_SECT_GS0 & MEMCFG_SECT_NUM_MASK;
    HWREG(MEMCFG_BASE + MEMCFG_O_GSXMSEL) |= MEMCFG_SECT_GS1 & MEMCFG_SECT_NUM_MASK;
    HWREG(MEMCFG_BASE + MEMCFG_O_GSXMSEL) |= MEMCFG_SECT_GS2 & MEMCFG_SECT_NUM_MASK;
    EDIS;
#endif
}



uint16_t Internal_flash_Erase(uint32_t Addr_start)
{
    uint16_t EraseErr = 0;
    //
    // Pump access must be gained by the core using pump semaphore
    //
#ifdef CPU1
    Flash_claimPumpSemaphore(FLASH_CPU1_WRAPPER);
#elif defined(CPU2)
    Flash_claimPumpSemaphore(FLASH_CPU2_WRAPPER);
#endif

    Fapi_FlashBankType oNewFlashBank;
//    uint16_t i = 0;
    Fapi_StatusType  oReturnCheck;

    oNewFlashBank = (Fapi_FlashBankType)Internal_flash_Sektor_Addr(Addr_start);

    //
    // Initialize the Flash API by providing the Flash register base address
    // and operating frequency(in MHz).
    // This function is required to initialize the Flash API based on System
    // frequency before any other Flash API operation can be performed.
    // This function must also be called whenever System frequency or RWAIT is
    // changed.
    //
    oReturnCheck = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS,
                                      DEVICE_SYSCLK_FREQ/1000000U);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        return(0x12);//Internal_flash_Error();
    }

    //
    // Initialize the Flash banks and FMC for erase and program operations.
    // function sets the Flash banks and FMC for
    // further Flash operations to be performed on the banks.
    //
    oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        return(0x12);//Internal_flash_Error();
    }


    // Erase the sector before programming
    //
    EraseErr = Internal_flash_lib_EraseSector(oNewFlashBank);
    //EraseErr = Internal_flash_lib_EraseSector(FlashBankStartAddr[oNewFlashBank]);

    //
    // Release the pump access
    //
    Flash_releasePumpSemaphore();

    return EraseErr;
    //
    // Example is done here
    //
    //Internal_flash_Done();
}


uint16_t Internal_flash_Program_AutoECC(uint32_t Addr_start, uint16_t Num)
{
    uint16_t EraseErr = 0;
    //
    // Pump access must be gained by the core using pump semaphore
    //
#ifdef CPU1
    Flash_claimPumpSemaphore(FLASH_CPU1_WRAPPER);
#elif defined(CPU2)
    Flash_claimPumpSemaphore(FLASH_CPU2_WRAPPER);
#endif

    Fapi_FlashBankType oNewFlashBank;
//    uint16_t i = 0;
    Fapi_StatusType  oReturnCheck;

    oNewFlashBank = (Fapi_FlashBankType)Internal_flash_Sektor_Addr(Addr_start);

    //
    // Initialize the Flash API by providing the Flash register base address
    // and operating frequency(in MHz).
    // This function is required to initialize the Flash API based on System
    // frequency before any other Flash API operation can be performed.
    // This function must also be called whenever System frequency or RWAIT is
    // changed.
    //
    oReturnCheck = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS,
                                      DEVICE_SYSCLK_FREQ/1000000U);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        return(0x12);//Internal_flash_Error();
    }

    //
    // Initialize the Flash banks and FMC for erase and program operations.
    // Fapi_setActiveFlashBank() function sets the Flash banks and FMC for
    // further Flash operations to be performed on the banks.
    //
    oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        return(0x12);//Internal_flash_Error();
    }

    //
    // Fill a buffer with data to program into the flash.
    //
    //for(i=0; i < WORDS_IN_FLASH_BUFFER; i++)
    //{
    //    Buffer[i] = i*2;
    //}

    //
    // Program the sector using AutoECC option
    //
    EraseErr = Internal_flash_lib_ProgramUsingAutoECC(Addr_start, Num);

    //
    // Release the pump access
    //
    Flash_releasePumpSemaphore();

    return EraseErr;
    //
    // Example is done here
    //
    //Internal_flash_Done();
}

uint16_t Internal_flash_Program_DataOnlyECCOnly(uint32_t Addr_start, uint16_t Num)
{
    uint16_t EraseErr = 0;
    //
    // Pump access must be gained by the core using pump semaphore
    //
#ifdef CPU1
    Flash_claimPumpSemaphore(FLASH_CPU1_WRAPPER);
#elif defined(CPU2)
    Flash_claimPumpSemaphore(FLASH_CPU2_WRAPPER);
#endif

    //uint16_t i = 0;
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashBankType oNewFlashBank;

    oNewFlashBank = (Fapi_FlashBankType)Internal_flash_Sektor_Addr(Addr_start);

    //
    // Initialize the Flash API by providing the Flash register base address
    // and operating frequency(in MHz).
    // This function is required to initialize the Flash API based on System
    // frequency before any other Flash API operation can be performed.
    // This function must also be called whenever System frequency or RWAIT is
    // changed.
    //
    oReturnCheck = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS,
                                      DEVICE_SYSCLK_FREQ/1000000U);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        return(0x12);//Internal_flash_Error();
    }

    //
    // Initialize the Flash banks and FMC for erase and program operations.
    // Fapi_setActiveFlashBank() function sets the Flash banks and FMC for
    // further Flash operations to be performed on the banks.
    //
    oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        return(0x12);//Internal_flash_Error();
    }

    //
    // Fill a buffer with data to program into the flash.
    //
    //for(i=0; i < WORDS_IN_FLASH_BUFFER; i++)
    //{
    //    Buffer[i] = i;
    //}


    //
    // Program the sector using DataOnly and ECCOnly options
    //
    EraseErr = Internal_flash_lib_ProgramUsingDataOnlyECCOnly(Addr_start, Num);
    //
    // Release the pump access
    //
    Flash_releasePumpSemaphore();

    return EraseErr;
    //
    // Example is done here
    //
    //Internal_flash_Done();
}


//*****************************************************************************
//  Example_ProgramUsingAutoECC
//
//  Example function to Program data in Flash using "AutoEccGeneration" option.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************

uint16_t Internal_flash_lib_ProgramUsingAutoECC(uint32_t Addr_start, uint16_t Num)
{
    uint32_t u32Index = 0;
    uint16_t i = 0;
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType  oFlashStatusWord;

    //
    // A data buffer of max 8 16-bit words can be supplied to the program
    // function.
    // Each word is programmed until the whole buffer is programmed or a
    // problem is found. However to program a buffer that has more than 8
    // words, program function can be called in a loop to program 8 words for
    // each loop iteration until the whole buffer is programmed.
    //
    // Remember that the main array flash programming must be aligned to
    // 64-bit address boundaries and each 64 bit word may only be programmed
    // once per write/erase cycle.  Meaning the length of the data buffer
    // (3rd parameter for Fapi_issueProgrammingCommand() function) passed
    // to the program function can only be either 4 or 8.
    //
    // Program data in Flash using "AutoEccGeneration" option.
    // When AutoEccGeneration option is used, Flash API calculates ECC for the
    // given 64-bit data and programs it along with the 64-bit main array data.
    // Note that any unprovided data with in a 64-bit data slice
    // will be assumed as 1s for calculating ECC and will be programmed.
    //
    // Note that data buffer (Buffer) is aligned on 64-bit boundary for verify
    // reasons.
    //
    // Monitor ECC address for the sector below while programming with
    // AutoEcc mode.
    //
    // In this example, the number of bytes specified in the flash buffer
    // are programmed in the flash sector below along with auto-generated
    // ECC.
    //

    for(i=0, u32Index = Addr_start;
       (u32Index < (Addr_start + Num));
       i+= 8, u32Index+= 8)
    {

        oReturnCheck = Fapi_issueProgrammingCommand((uint32_t *)u32Index,Buffer+i,
                                               8, 0, 0, Fapi_AutoEccGeneration);

        //
        // Wait until the Flash program operation is over
        //
        while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            return(0x12);//Internal_flash_Error();
        }

        //
        // Read FMSTAT register contents to know the status of FSM after
        // program command to see if there are any program operation related
        // errors
        //
        oFlashStatus = Fapi_getFsmStatus();
        if(oFlashStatus != 0)
        {
            //
            //Check FMSTAT and debug accordingly
            //
            return(0x13);//Internal_flash_Fail();
        }

        //
        // Verify the programmed values.  Check for any ECC errors.
        //
        oReturnCheck = Fapi_doVerify((uint32_t *)u32Index,
                                     4, Buffer32+(i/2),
                                     &oFlashStatusWord);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            return(0x12);//Internal_flash_Error();
        }
    }
    return(0);
}

//*****************************************************************************
//  Example_ProgramUsingDataOnlyECCOnly
//
//  Example function to Program data in Flash using "DataOnly" option and ECC
//  using "EccOnly" option.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************

uint16_t Internal_flash_lib_ProgramUsingDataOnlyECCOnly(uint32_t Addr_start, uint16_t Num)
{
    uint32_t u32Index = 0;
    uint16_t i = 0, ECC_B = 0, ECC_LB = 0, ECC_HB = 0;
    uint64_t *LData, *HData, dataLow, dataHigh;
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType  oFlashStatusWord;

    //
    // Program data using "DataOnly" option and ECC using "EccOnly" option.
    //
    // When DataOnly option is used, Flash API will program only the data
    // portion in Flash at the address specified.
    //
    // When EccOnly option is used, Flash API will program only the ECC portion
    // in Flash ECC memory space (Flash main array address should be provided
    // for this function and not the corresponding ECC address).
    // Fapi_calculateEcc is used to calculate the corresponding ECC of the data.
    //
    // Note that data buffer (Buffer) is aligned on 64-bit boundary for verify
    // reasons.
    //
    // In this example, 0x100 bytes are programmed in Flash Sector6
    // along with the specified ECC.
    //

    for(i=0, u32Index = Addr_start;
       (u32Index < (Addr_start + Num));
       i+= 8, u32Index+= 8)
    {
        //
        // Point LData to the lower 64 bit data
        // and   HData to the higher 64 bit data
        //
        LData = (uint64 *)(Buffer32 + i/2);
        HData = (uint64 *)(Buffer32 + i/2 + 2);

        //
        // Calculate ECC for lower 64 bit and higher 64 bit data
        //
        ECC_LB = Fapi_calculateEcc(u32Index,*LData);
        ECC_HB = Fapi_calculateEcc(u32Index+4,*HData);
        ECC_B = ((ECC_HB<<8) | ECC_LB);

        oReturnCheck = Fapi_issueProgrammingCommand((uint32_t *)u32Index,Buffer+i,
                                                        8, 0, 0, Fapi_DataOnly);

        //
        // Wait until the Flash program operation is over
        //
        while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            return(0x12);//Internal_flash_Error();
        }

        //
        // Read FMSTAT register contents to know the status of FSM after
        // program command to see if there are any program operation related
        // errors
        //
        oFlashStatus = Fapi_getFsmStatus();
        if(oFlashStatus != 0)
        {
            //Check FMSTAT and debug accordingly
            return(0x13);//Internal_flash_Fail();
        }
        oReturnCheck = Fapi_issueProgrammingCommand((uint32_t *)u32Index, 0, 0,
                                                    &ECC_B, 2, Fapi_EccOnly);

        //
        // Wait until the Flash program operation is over
        //
        while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            return(0x12);//Internal_flash_Error();
        }

        //
        // Read FMSTAT register contents to know the status of FSM after
        // program command to see if there are any program operation related
        // errors
        //
        oFlashStatus = Fapi_getFsmStatus();
        if(oFlashStatus != 0)
        {
            //
            // Check FMSTAT and debug accordingly
            //
            return(0x13);//Internal_flash_Fail();
        }

        Flash_enableECC(FLASH0ECC_BASE);
        //
        // Read back the programmed data to check if there are any ECC failures
        //
        dataLow = *(uint64 *)(u32Index);

        Flash_ErrorStatus errorStatusLow = Flash_getLowErrorStatus(FLASH0ECC_BASE);
        if((errorStatusLow != FLASH_NO_ERR) || (dataLow != *LData))
        {
            return(0x14);//Internal_flash_ECC_Fail();
        }

        dataHigh = *(uint64 *)(u32Index + 4);

        Flash_ErrorStatus errorStatusHigh = Flash_getHighErrorStatus(FLASH0ECC_BASE);
        if((errorStatusHigh != FLASH_NO_ERR) || (dataHigh != *HData))
        {
            return(0x14);//Internal_flash_ECC_Fail();
        }


        //
        // Verify the programmed values.  Check for any ECC errors.
        //
        oReturnCheck = Fapi_doVerify((uint32_t *)u32Index,
                                     4, Buffer32+(i/2),
                                     &oFlashStatusWord);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            return(0x12);//Internal_flash_Error();
        }
    }
    return(0);
}

//*****************************************************************************
//  Example_ProgramUsingDataAndECC
//
//  Example function to Program data in Flash using "DataAndEcc" option.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************

uint16_t Internal_flash_lib_ProgramUsingDataAndECC(uint32_t Addr_start, uint16_t Num)
{
    uint32_t u32Index = 0;
    uint16_t i = 0, ECC_B = 0, ECC_LB = 0, ECC_HB = 0;
    uint64_t *LData, *HData, dataLow, dataHigh;
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType  oFlashStatusWord;

    //
    // Program data and ECC in Flash using "DataAndEcc" option.
    // When DataAndECC option is used, Flash API will program both the supplied
    // data and ECC in Flash at the address specified.
    // Fapi_calculateEcc is used to calculate the corresponding ECC of the data.
    //
    // Note that data buffer (Buffer) is aligned on 64-bit boundary for verify
    // reasons.
    //
    // In this example, 0x100 bytes are programmed in Flash Sector6
    // along with the specified ECC.
    //

    for(i=0, u32Index = Addr_start;
       (u32Index < (Addr_start + Num));
       i+= 8, u32Index+= 8)
    {
        //
        // Point LData to the lower 64 bit data
        // and   HData to the higher 64 bit data
        //
        LData = (uint64 *)(Buffer32 + i/2);
        HData = (uint64 *)(Buffer32 + i/2 + 2);

        //
        // Calculate ECC for lower 64 bit and higher 64 bit data
        //
        ECC_LB = Fapi_calculateEcc(u32Index,*LData);
        ECC_HB = Fapi_calculateEcc(u32Index+4,*HData);
        ECC_B = ((ECC_HB<<8) | ECC_LB);

        oReturnCheck = Fapi_issueProgrammingCommand((uint32_t *)u32Index,Buffer+i,
                                                 8, &ECC_B, 2, Fapi_DataAndEcc);

        //
        // Wait until the Flash program operation is over
        //
        while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            return(0x12);//Internal_flash_Error();
        }

        //
        // Read FMSTAT register contents to know the status of FSM after
        // program command to see if there are any program operation related
        // errors
        //
        oFlashStatus = Fapi_getFsmStatus();
        if(oFlashStatus != 0)
        {
            //
            // Check FMSTAT and debug accordingly
            //
            return(0x13);//Internal_flash_Fail();
        }

        Flash_enableECC(FLASH0ECC_BASE);

        //
        // Read back the programmed data to check if there are any ECC failures
        //
        dataLow = *(uint64 *)(u32Index);

        Flash_ErrorStatus errorStatusLow = Flash_getLowErrorStatus(FLASH0ECC_BASE);
        if((errorStatusLow != FLASH_NO_ERR) || (dataLow != *LData))
        {
            return(0x14);//Internal_flash_ECC_Fail();
        }

        dataHigh = *(uint64 *)(u32Index + 4);

        Flash_ErrorStatus errorStatusHigh = Flash_getHighErrorStatus(FLASH0ECC_BASE);
        if((errorStatusHigh != FLASH_NO_ERR) || (dataHigh != *HData))
        {
            return(0x14);//Internal_flash_ECC_Fail();
        }

        //
        // Verify the programmed values.  Check for any ECC errors.
        //
        oReturnCheck = Fapi_doVerify((uint32_t *)u32Index,
                                     4, Buffer32+(i/2),
                                     &oFlashStatusWord);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            return(0x12);//Internal_flash_Error();
        }
    }
    return(0);
}

//*****************************************************************************
//  Example_EraseSector
//
//  Example function to Erase data of a sector in Flash.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************

uint16_t Internal_flash_lib_EraseSector(uint16_t oNewFlashBank)
{
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType  oFlashStatusWord;

    uint32_t Addr_start = FlashBankStartAddr[oNewFlashBank];

    //
    // Erase the sector that is programmed in the above example
    // Erase Sector6
    //
    oReturnCheck = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector,
                   (uint32_t *)Addr_start);
    //
    // Wait until FSM is done with erase sector operation
    //
    while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady){}

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        return(0x12);//Internal_flash_Error();
    }

    //
    // Read FMSTAT register contents to know the status of FSM after
    // erase command to see if there are any erase operation related errors
    //
    oFlashStatus = Fapi_getFsmStatus();
        if(oFlashStatus != 0)
    {
        //
        // Check Flash API documentation for FMSTAT and debug accordingly
        // Fapi_getFsmStatus() function gives the FMSTAT register contents.
        // Check to see if any of the EV bit, ESUSP bit, CSTAT bit or
        // VOLTSTAT bit is set (Refer to API documentation for more details).
        //
        return(0x13);//Internal_flash_Fail();
    }

    //
    // Verify that Sector6 is erased
    //Sector64KB_u32length
    oReturnCheck = Fapi_doBlankCheck((uint32_t *)Addr_start, Sector_length[oNewFlashBank], &oFlashStatusWord);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for error info
        //
        return(0x12);//Internal_flash_Error();
    }
    return(0);
}


