/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2016. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */

#include <stdint.h>
#include "ac780x.h" 
#include "ac780x_eflash.h" 
#include "status.h"

#ifndef NULL_PTR
#define NULL_PTR ((void *)0)
#endif
typedef void (* flash_callback_t)(void);
typedef struct
{
    uint32_t PFlashBase;          /*!< The base address of P-Flash memory */
    uint32_t PFlashSize;          /*!< The size in byte of P-Flash memory */
    uint32_t DFlashBase;          /*!< For FlexNVM device, this is the base address of D-Flash memory (FlexNVM memory);
                                   *    For non-FlexNVM device, this field is unused */
    uint32_t DFlashSize;          /*!< For FlexNVM device, this is the size in byte of area
                                   *    which is used as D-Flash from FlexNVM memory;
                                   *    For non-FlexNVM device, this field is unused */
    uint32_t EERAMBase;           /*!< The base address of FlexRAM (for FlexNVM device)
                                   *    or acceleration RAM memory (for non-FlexNVM device) */
    uint32_t EEESize;             /*!< For FlexNVM device, this is the size in byte of EEPROM area which was partitioned
                                   *    from FlexRAM; For non-FlexNVM device, this field is unused */
    flash_callback_t CallBack;    /*!< Call back function to service the time critical events. Any code reachable from this function
                                   *   must not be placed in a Flash block targeted for a program/erase operation */
} flash_ssd_config_t;
typedef struct
{
    status_t (*FLASH_EraseAllBlock)(const flash_ssd_config_t * pSSDConfig);
    status_t (*FLASH_VerifyAllBlock)(const flash_ssd_config_t * pSSDConfig,uint8_t marginLevel);
    status_t (*FLASH_EraseSector)(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint32_t size);
    status_t (*FLASH_VerifySection)(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint16_t number,uint8_t marginLevel);
    void (*FLASH_EraseSuspend)(void);
    void (*FLASH_EraseResume)(void);
    status_t (*FLASH_Program)(const flash_ssd_config_t * pSSDConfig,uint32_t dest, uint32_t size,const uint8_t * pData);
    status_t (*FLASH_ProgramCheck)(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint32_t size,const uint8_t * pExpectedData,uint32_t * pFailAddr,uint8_t marginLevel);
    status_t (*FLASH_ProgramSection)(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint16_t number);
    status_t (*FLASH_EraseBlock)(const flash_ssd_config_t * pSSDConfig, uint32_t dest);
    status_t (*FLASH_CommandSequence)(const flash_ssd_config_t * pSSDConfig);
    status_t (*FLASH_VerifyBlock)(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint8_t marginLevel);
} tFlashOptInfo;

status_t eFLASH_EraseAllBlock(const flash_ssd_config_t * pSSDConfig);
status_t eFLASH_VerifyAllBlock(const flash_ssd_config_t * pSSDConfig,uint8_t marginLevel);
status_t eFLASH_EraseSector(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint32_t size);
status_t eFLASH_VerifySection(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint16_t number,uint8_t marginLevel);
status_t eFLASH_Program(const flash_ssd_config_t * pSSDConfig,uint32_t dest, uint32_t size,const uint8_t * pData);
status_t eFLASH_ProgramCheck(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint32_t size,const uint8_t * pExpectedData,uint32_t * pFailAddr,uint8_t marginLevel);
status_t eFLASH_ProgramSection(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint16_t number);
status_t eFLASH_EraseBlock(const flash_ssd_config_t * pSSDConfig, uint32_t dest);
status_t eFLASH_VerifyBlock(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint8_t marginLevel);
#pragma arm section rodata = "RESET"
const tFlashOptInfo g_stFlashOptInfo =
{
    NULL_PTR,
    NULL_PTR,
    &eFLASH_EraseSector,
    &eFLASH_VerifySection,
    NULL_PTR,
    NULL_PTR,
    &eFLASH_Program,
    &eFLASH_ProgramCheck,
    NULL_PTR,
    NULL_PTR,
    NULL_PTR,
    NULL_PTR,
};
#pragma arm section rodata
status_t eFLASH_EraseAllBlock(const flash_ssd_config_t * pSSDConfig)
{
    return STATUS_ERROR;
}
status_t eFLASH_VerifyAllBlock(const flash_ssd_config_t * pSSDConfig,uint8_t marginLevel)
{
    return STATUS_ERROR;
}
status_t eFLASH_EraseSector(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint32_t size)
{
    uint32_t eraseSize=0;
    if((dest & 0x7ff) != 0) ///<must be start addr of a sector
    {
        return STATUS_ERROR;
    }
    
    EFLASH_UnlockCtrl();
    while (eraseSize < size)
    {
        EFLASH_PageErase(dest + eraseSize);
        eraseSize += 0x800;
    }
    EFLASH_LockCtrl();
    return STATUS_SUCCESS;
}
status_t eFLASH_VerifySection(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint16_t number,uint8_t marginLevel)
{
    return STATUS_SUCCESS;
}
status_t eFLASH_Program(const flash_ssd_config_t * pSSDConfig,uint32_t dest, uint32_t size,const uint8_t * pData)
{
    EFLASH_UnlockCtrl();
    EFLASH_PageProgram(dest, (uint32_t *)pData, size>>2);
    EFLASH_LockCtrl();
    return STATUS_SUCCESS;
}
status_t eFLASH_ProgramCheck(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint32_t size,const uint8_t * pExpectedData,uint32_t * pFailAddr,uint8_t marginLevel)
{
    uint32_t i; 
    for (i=0;i<size;i++)
    {
        if (*(uint8_t *)(dest+i) != pExpectedData[i])
        {
            *pFailAddr = dest+i;
            return STATUS_ERROR;
        }
    }
    return STATUS_SUCCESS;
}
status_t eFLASH_ProgramSection(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint16_t number)
{
    return STATUS_ERROR;
}
status_t eFLASH_EraseBlock(const flash_ssd_config_t * pSSDConfig, uint32_t dest)
{
    return STATUS_ERROR;
}
status_t eFLASH_VerifyBlock(const flash_ssd_config_t * pSSDConfig,uint32_t dest,uint8_t marginLevel)
{
    return STATUS_ERROR;
}
