/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

#ifndef _FLASH_DRV_H_
#define _FLASH_DRV_H_

/*! \brief Contains public interface to various functions related
 *         to the driver of FLASH
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include <stdbool.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
 * the defines
 ******************************************************************************/
/*! \brief Macro for high and low position separation of the memory address.
 *
 * The 32-bit address need to be sperated to 8-bit and then programmed to
 * specific fccob registers.
 */
#define FCCOBADDRLOW(addr)      ((uint8_t)(((uint32_t)(addr)) & 0xFFU))
#define FCCOBADDRMDLOW(addr)    ((uint8_t)((((uint32_t)(addr)) >> 8) & 0xFFU))
#define FCCOBADDRMDHIG(addr)    ((uint8_t)((((uint32_t)(addr)) >> 16) & 0xFFU))
#define FCCOBADDRHIG(addr)      ((uint8_t)(((uint32_t)(addr)) >> 24))

/*! \brief Macro for the alignment requirement.
 *
 * The address need to be aligned.
 */
#define ALIGNED(val, alncnt)    (((uint32_t)val) & ~(alncnt - 1))
#define IS_ALIGNED(val, alncnt) ((((uint32_t)val) & (alncnt - 1)) == 0x0 ? true : false)

/*! \brief Macro for sector size
 *
 * Sector size is 1024.
 */
#define FLASHDRV_SECTOR_SIZE    (1024U)

/*! \brief Macro for the byte count of phrase-write and phrase-read
 *
 * phrase-write/phrase-read size
 */
#define FLASHDRV_PHRASE_SIZE    (8U)

/*! \brief Macro for the flexram address
 *
 * flexram address
 */
#define FLASHDRV_FLEXRAM_ADDR   (0x14000000UL)

/*! \brief Macro for the flexram size
 *
 * flexram size
 */
#define FLASHDRV_FLEXRAM_SIZE   (2048U)

/*******************************************************************************
 * the typedefs
 ******************************************************************************/

/*! \brief Status return codes.
 * Common error codes will be a unified enumeration (C enum) that will contain
 * all error codes (common and specific). There will be separate "error values
 * spaces" (or slots), each of 256 positions, allocated per functionality.
 */
typedef enum
{
    /* Generic error codes */
    FLASHDRV_STATUS_SUCCESS     = 0x000U, /*!< Generic operation success status */
    FLASHDRV_STATUS_ERROR       = 0x001U, /*!< Generic operation failure status */
    FLASHDRV_STATUS_BUSY        = 0x002U, /*!< Generic operation busy status */
    FLASHDRV_STATUS_TIMEOUT     = 0x003U, /*!< Generic operation timeout status */
    FLASHDRV_STATUS_UNSUPPORTED = 0x004U, /*!< Generic operation unsupported status */
} FlashDrv_Status;

/*! \brief FLASH type of operation cmd
 */
typedef enum
{
    FLASHDRV_OPCMD_BLKRD1S   = 0x00, /*!< Block Read 1s command*/
    FLASHDRV_OPCMD_SCTRD1S   = 0x01, /*!< Section Read 1s command*/
    FLASHDRV_OPCMD_PRSCHK    = 0x02, /*!< Phrase check command*/
    FLASHDRV_OPCMD_PRSPGM    = 0x03, /*!< Phrase Program command*/
    FLASHDRV_OPCMD_BLKERS    = 0x04, /*!< Block Erase command*/
    FLASHDRV_OPCMD_SCTERS    = 0x05, /*!< Sector Erase command*/
    FLASHDRV_OPCMD_SCTPGM    = 0x06, /*!< Program section command*/
    FLASHDRV_OPCMD_ALBLKRD1S = 0x07, /*!< Read 1s ALL Blocks command*/
    FLASHDRV_OPCMD_RDINFORG  = 0x08, /*!< Read once command: for info region*/
    FLASHDRV_OPCMD_PGMINFORG = 0x09, /*!< Program once command: for info region*/
    FLASHDRV_OPCMD_ALBLKERS  = 0x0A, /*!< Erase ALL blocks command*/
    FLASHDRV_OPCMD_VRFYKEY   = 0x0B, /*!< Verify backdoor access key command*/
    FLASHDRV_OPCMD_ALBLKUERS = 0x0C, /*!< Erase All Blocks unsecure command*/
    FLASHDRV_OPCMD_SETFRAM   = 0x0D, /*!< Set Flexram command*/
} FlashDrv_Opcmd_t;

/*! \brief FLASH info region type
 */
typedef enum
{
    FLASHDRV_INFORG0 = 0x00, /*!< info region,512bytes, phrase_index: 0~ 63, no erase cmd*/
} FlashDrv_InfoRegion_t;

/*! \brief FLASH sector erase type
 */
typedef enum
{
    FLASHDRV_SCTERS_ONEPULSE = 0x00, /*!< one-pulse erase */
    FLASHDRV_SCTERS_RETRY    = 0x01, /*!< retry erase     */
} FlashDrv_SectorErase_t;

/*! \brief Definition for the flash cmd done callback function.
 *
 * Prototype for the callback function registered in the flash driver.
 */
typedef void (*FlashDrv_CallBackType)(void);

/*! \brief Definition of configuration of FLASH driver
 */
typedef struct _FlashDrv_ConfigType_
{
    uint32_t              pflashbase; /*!< The base address of P-Flash memory */
    uint32_t              pflashsize; /*!< The size in byte of P-Flash memory */
    uint32_t              dflashbase; /*!< The base address of D-Flash memory */
    uint32_t              dflashsize; /*!< The size in byte of P-Flash memory */
    bool                  eeevld;     /*!< emualted ee function valid flag*/
    FlashDrv_CallBackType 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 */
} FlashDrv_ConfigType;

/* Forward declaration of flash ftfc register */
struct _FtfcRegType_;
/* Forward declaration of Scg0 register */
struct _Scg0RegType_;

/*! \brief The definition of flash driver class
 */
typedef struct _FlashDrvType_
{
    struct _FtfcRegType_ *reg;
    struct _Scg0RegType_ *scg0Reg;
    uint32_t              pflashbase; /*!< The base address of P-Flash memory */
    uint32_t              pflashsize; /*!< The size in byte of P-Flash memory */
    uint32_t              dflashbase; /*!< The base address of D-Flash memory */
    uint32_t              dflashsize; /*!< The size in byte of P-Flash memory */
    bool                  eeevld;     /*!< emualted ee function valid flag*/
    FlashDrv_CallBackType 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 */
} FlashDrvType;

/*******************************************************************************
 * the globals
 ******************************************************************************/

/*******************************************************************************
 * the function prototypes
 ******************************************************************************/

/*! \brief Initializes the Flash driver module
 *
 * This function initializes Flash driver by setting the register
 * instance to it.
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] reg : pointer to Flash register instance
 * \param[in] scg0Reg : pointer to SCG0 register instance
 */
extern void FlashDrv_Init(FlashDrvType *obj, struct _FtfcRegType_ *reg, struct _Scg0RegType_ *scg0Reg);

/*! \brief Get configures of the Flash module currently
 *
 * This function gets configures of the Flash module currently
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[out] userConfig : pointer to configuration structure
 */
extern void FlashDrv_GetConfig(const FlashDrvType  *obj,
                               FlashDrv_ConfigType *userconfig);

/*! \brief Get default configures the Flash module for configuration structure
 *
 * This function gets default configures the Flash module for user configuration
 * structure
 *
 * \param[out] userConfig : pointer to configuration structure
 */
extern void FlashDrv_GetDefaultConfig(FlashDrv_ConfigType *userconfig);

/*! \brief Configures the Flash module from a user configuration structure
 *
 * This function configures the Flash module from a user configuration structure
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] userConfig : pointer to configuration structure
 */
extern void FlashDrv_Configure(FlashDrvType              *obj,
                               const FlashDrv_ConfigType *userconfig);

/*! \brief Verify the Pflash or Dfalsh(keysector included) erased
 *
 * This function verify pflash or dflash is erased.
 *
 * NOTE：if targeted block is the eee backup region,
 *       the read1s seqeunce will be aborted
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] destaddr : pointer to a memory address in pflash/dflash
 */
extern FlashDrv_Status FlashDrv_Read1sBlock(FlashDrvType *obj,
                                            uint32_t     *destaddr);

/*! \brief Verify a section erased
 *
 * This function verify a section erased. The section should located in a sector
 * or should be a total sector. Both the start addr and the size of the section
 * are supposed to be 8-aligned.
 *
 * NOTE:if targeted section is in the eee backup region, the
 *      erase sequence will be aborted.
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] destaddr : pointer to a memory address in pflash or dflash:8-aligned.
 * \param[in] rdsize : length of read/verified memory in bytes:8-aligned.
 */
extern FlashDrv_Status FlashDrv_Read1sSection(FlashDrvType *obj,
                                              uint32_t     *destaddr,
                                              uint32_t      rdsize);

/*! \brief Check a phrase programmed as expected value
 *
 * This function checked a phrase-data[8bytes] progrmmed as expected value.
 * The phrase addr is supposed to be 8-aligned.
 *
 * NOTE:if targeted phrase is in the eee backup region, the
 *      checkphrase sequence will be aborted.
 *
 * \param[in] obj : pointer to Flash driver instance.
 * \param[in] destaddr : pointer to a phrase address in pflash or dflash,8-aligned.
 * \param[in] expdata : pointor to expected data, 8 bytes
 */
extern FlashDrv_Status FlashDrv_CheckPhrase(FlashDrvType *obj,
                                            uint32_t     *destaddr,
                                            uint8_t      *expdata);

/*! \brief Check a phrase has ecc error
 *
 * This function checked a phrase-data[8bytes] has ecc error.
 *
 *
 * \param[in] obj : pointer to Flash driver instance.
 * \param[in] destaddr : pointer to a memory address in pflash or dflash, 8-aligned.
 */
extern FlashDrv_Status FlashDrv_CheckEccState(FlashDrvType *obj,
                                              uint32_t     *destaddr);

/*! \brief Program a phrase as expected value
 *
 * This function checked a phrase-data[8bytes/9bytes] progrmmed as expected
 * value. The phrase addr is supposed to be 8-aligned.
 *
 * NOTE: 1.make sure targeted phrase is erased and not proteted before
 * programmed; 2.if the target section is in the eee backup region,
 * the program sequence will be aborted.
 *
 * \param[in] obj : pointer to Flash driver instance.
 * \param[in] destaddr : pointer to a memory address in pflash or dflash,8-aligned.
 * \param[in] expdata : pointor to expected data, 8 bytes or 9 bytes
 * \param[in] hweccen : true: first 8 bytes will be programmed,ecc byte programmed by hardware;
 *                      false: 9 bytes(ecc byte included) will be programmed;
 */
extern FlashDrv_Status FlashDrv_ProgramPhrase(FlashDrvType *obj,
                                              uint32_t     *destaddr,
                                              uint8_t      *expdata,
                                              bool          hweccen);

/*! \brief Erase Pflash or Dfalsh
 *
 * This function erase pflash or dflash.
 *
 * NOTE:
 *    1.Any code reachable from this function must not be placed in a Flash
 * block targeted for this erase operation. 2.Between the POR and Pflash-erased
 * operations, remind to program pflash-cfg-feild[0x400~0x41f] to proper
 * value.Otherwise, system will enter security state, swd cannot be connected.
 * 3.if there is protection region in targeted block, the erase
 * sequence will be aborted; 4.if targeted flash is the eee backup region,
 * the erase sequence will be aborted.
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] destaddr : pointer to a address in pflash or dflash, 8-aligned
 * \param[in] erasetype: erase type
 */
extern FlashDrv_Status FlashDrv_EraseBlock(FlashDrvType          *obj,
                                           uint32_t              *destaddr,
                                           FlashDrv_SectorErase_t erasetype);

/*! \brief Erases a sector
 *
 * This function erases a sector located in pflash or dflash.
 *
 * NOTE:
 *    1.Any code reachable from this function must not be placed in the targeted setcor.
 *    2.if the sector[address:0x400~0x7ff] erased, before the POR, remind to program
 *    pflash-cfg-feild[0x400~0x41f] to proper value.Otherwise, system will enter security state,
 *     swd cannot be connected anymore
 *    3.if the sector is in the eee backup region, the erase sequence will
 *     be aborted.
 *    4.if the targeted sector is in protection region,the erase sequence will be aborted
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] destaddr : pointer to a address in the targeted sector
 * \param[in] erasetype: erase type
 */
extern FlashDrv_Status FlashDrv_EraseSector(FlashDrvType          *obj,
                                            uint32_t              *destaddr,
                                            FlashDrv_SectorErase_t erasetype);

/*! \brief Programs a section
 *
 * This function programs a section. The section should located in a sector or
 * should be a total sector. Both the start addr and the size of the section are
 * supposed to be 256-aligned.
 *
 * NOTE: 1.make sure targeted section is erased and not proteted before
 * programmed; 2.if the target section is in the eee backup region,
 * the program sequence will be aborted.
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] destaddr : pointer to a memory address in the targeted sector,256-aligned
 * \param[in] len : length of programmed data in bytes, 256-aligned
 * \param[in] databuf : pointer to source data
 */
extern FlashDrv_Status FlashDrv_ProgramSection(FlashDrvType *obj,
                                               uint32_t     *destaddr,
                                               uint32_t      len,
                                               uint8_t      *databuf);

/*! \brief Programs a section
 *
 * This function programs a section fastly. The section should located in a sector or
 * should be a total sector. Both the start addr and the size of the section are
 * supposed to be 256-aligned. The programmed data is supposed to be prepared already in the flexram.
 *
 * NOTE: 1.make sure targeted section is erased and not proteted before
 * programmed; 2.if the target section is in the eee backup region,
 * the program sequence will be aborted.3.the programmed data has been placed in the flexram with
 * correct offset(offset = dest & (FLASHDRV_SECTOR_SIZE - 1)) while ram ready.
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] destaddr : pointer to a memory address in the targeted sector,256-aligned
 * \param[in] len : length of programmed data in bytes, 256-aligned
 */
extern FlashDrv_Status FlashDrv_ProgramSectionFast(FlashDrvType *obj,
                                                   uint32_t     *destaddr,
                                                   uint32_t      len);

/*! \brief verify all blocks(pflash,dflash/e-flash) erased.
 *
 * This function verify all blocks [pflash,dflash]erased.
 *
 * NOTE: 1.make sure no proteted region in flash, otherwise the read1s sequence will
 *  be aborted;
 *
 * \param[in] obj : pointer to Flash driver instance
 */
extern FlashDrv_Status FlashDrv_Read1sAllBlock(FlashDrvType *obj);

/*! \brief Reads a phrase(8 bytes) from flash info_region
 *
 * This function Read a phrase(8 bytes) from pflash info region or dflash info
 * region.
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] regionid : FLASHDRV_INFORGN0
 * \param[in] phraseid : index of the phrase in the info region sector, 0 ~ 63
 * \param[in] databuf  : pointer to a 8-byte-len buffer which data read from info region and write to
 */
extern FlashDrv_Status FlashDrv_ReadInfoRegion(FlashDrvType         *obj,
                                               FlashDrv_InfoRegion_t regionid,
                                               uint8_t               phraseid,
                                               uint8_t              *databuf);

/*! \brief Programs a phrase(8 bytes) into flash info_region
 *
 * This function programs a phrase(8 bytes) into flash info_region
 *
 * NOTE: 1.make sure the targeted phrase can be programmed only one time through the lifecycle;
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] regionid : FLASHDRV_INFORGN0
 * \param[in] phraseid : index of the phrase in the info region sector, 0 ~ 63
 * \param[in] databuf  : pointer to a 8-byte-len buffer which data read from info region and write to
 */
extern FlashDrv_Status FlashDrv_ProgramInfoRegion(FlashDrvType         *obj,
                                                  FlashDrv_InfoRegion_t regionid,
                                                  uint32_t              phraseid,
                                                  uint8_t              *databuf);

/*! \brief Erases all blocks(pflash, dflash/eflash, info-region).
 *
 * This function erases pflash, dflash/eflash, info-region.
 *
 * NOTE:
 *    1.Any code reachable from this function must not be placed in a Flash
 * block targeted for this erase operation. 2.Between the POR and
 * allblock-erased operations, remind to program pflash-cfg-feild[0x400~0x41f]
 * to proper value.Otherwise, system will enter security state, swd cannot be
 * connected anymore. 3.if there is protection region in flash, the erase sequence
 * will be aborted
 *
 * \param[in] obj : pointer to Flash driver instance
 */
extern FlashDrv_Status FlashDrv_EraseAllBlock(FlashDrvType *obj);

/*! \brief Erases all blocks and update security bit in flash security info
 * field.
 *
 * This function erase pflash,dflash/eflash, flash-info region ,and then program
 * the security bit in flash security info field.
 *
 * NOTE:
 *    1.Any code reachable from this function must not be placed in a Flash
 * block targeted for this erase operation. 2.if MEEN disbled, the erase sequence
 * will be aborted
 *
 * \param[in] obj : pointer to Flash driver instance
 */
extern FlashDrv_Status FlashDrv_EraseAllBlockUnsecure(FlashDrvType *obj);

/*! \brief Verify the user backdoor key and make the system enter unsecurity
 * state if pass.
 *
 * This function verify the user backdoor key stored in 0x400 with expected
 * data.If the verified pass,the system will enter un-security state.
 *
 * NOTE: 1.if the KEY-EN disabled, this sequence will be aborted;
 *
 * \param[in] obj : pointer to Flash driver instance.
 * \param[in] expdata : pointor to expected key-value, 8 bytes, supposed not to
 *                      be all-0s or all-1s.
 */
extern FlashDrv_Status FlashDrv_VerifyUserKey(FlashDrvType *obj,
                                              uint8_t      *expdata);

/*! \brief flash command done interrupt handler.
 *
 * \param[in] obj : pointer to Flash driver instance.
 */
extern void FlashDrv_IrqHandler(FlashDrvType *obj);

/*! \brief flash command done interrupt enable in flash driver side.
 *
 * \param[in] obj : pointer to Flash driver instance.
 * \param[in] en  : control flag for the flash command done interrupter enable or disable
 */
extern void FlashDrv_SetCmdDoneIrqEn(FlashDrvType *obj, bool en);

/*! \brief Get eee enable state
 *
 * This function gets the eee enable state
 *
 * \param[in] obj : pointer to Flash driver instance
 * \return eee enable state
 *         - false : eee not enabled in Eeprom Cfg field.If EEE enable expected, progroram InfoRegion with correct data and then POR
 *         - true  : eee enabled in Eeprom Cfg field
 */
extern bool FlashDrv_GetEeeEn(FlashDrvType *obj);

/*! \brief Get eee_ram ready state
 *
 * This function gets the eeerst enable state
 *
 * \param[in] obj : pointer to Flash driver instance
 * \return Eee_ram ready state
 *         - false : eee_ram not ready.
 *         - true  : eee_ram ready.
 */
extern bool FlashDrv_GetEeeRamRdy(FlashDrvType *obj);

/*! \brief sets the flexram as eee_ram or system_ram.
 *
 * \param[in] obj : pointer to Flash driver instance.
 * \param[in] eeeramen  : control eee_ram enabled or disabled,
 *             -false : the flex_ram will be used as system_ram
 *             -true : the flex_ram will be used as eeeram, UpdateEeeRam will take effect
 */
extern FlashDrv_Status FlashDrv_SetFlexRam(FlashDrvType *obj, bool eeeramen);

/*! \brief updates eee_ram, data will be stored in flash.
 *
 *NOTE: 1.makesure the auto_gc(SCG0_Inst:TRIM_AUTO_GC_EN) enabled before this function called to
 *    avoid data overflowing and lost
 *      2.makesure the eee_ram is enabled otherwise the new data will be lost
 *
 * \param[in] obj : pointer to Flash driver instance.
 * \param[in] offset : indicates the targeted position in the eee_ram, range is [0 ~ 2048]
 * \param[in] srcdata : pointer to srcdata which will be wrote into eee_ram
 * \param[in] sz: len of srcdata in byte
 */
extern FlashDrv_Status FlashDrv_UpdateEeeRam(FlashDrvType *obj, uint32_t offset, uint8_t *srcdata, uint32_t sz);

/*! \brief Gets eee auto GC enable state
 *
 * This function gets the eee auto GC enable state
 *
 * \param[in] obj : pointer to Flash driver instance
 * \return eee auto GC enable state
 *         - false : eee auto GC disabled
 *         - true  : eee auto GC enabled
 */
extern bool FlashDrv_GetEeeAutoGcEn(FlashDrvType *obj);

/*! \brief Sets eee auto GC enable
 *
 * This function sets the eee auto GC enabled or disabled
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[in] eeegcen  : control eee auto gc enabled or disabled,
 *             -false : the eee auto gc disabled
 *             -true :  the eee auto gc enabled
 */
extern void FlashDrv_SetEeeAutoGcEn(FlashDrvType *obj, bool eeegcen);

/*! \brief Gets eee_ram protection property
 *
 * This function gets the eee_ram protection property
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[out] protectStatus : pointer to protection status
 *                    - 0b : unprotect
 *                    - 1b : protect
 */
extern FlashDrv_Status FlashDrv_GetEeeRamProtection(FlashDrvType *obj, uint8_t *protectstatus);

/*! \brief Gets PFlash protection property
 *
 * This function gets the PFlash protection property
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[out] protectStatus : pointer to protection status
 *                    - 0b : unprotect
 *                    - 1b : protect
 */
extern FlashDrv_Status FlashDrv_GetPFlashProtection(FlashDrvType *obj, uint32_t *protectstatus);

/*! \brief Gets DFlash protection property
 *
 * This function gets the DFlash protection property
 *
 * \param[in] obj : pointer to Flash driver instance
 * \param[out] protectStatus : pointer to protection status
 *                    - 0b : unprotect
 *                    - 1b : protect
 */
extern FlashDrv_Status FlashDrv_GetDFlashProtection(FlashDrvType *obj, uint8_t *protectstatus);

#ifdef __cplusplus
}
#endif /* extern "C" */

#endif /* _FLASH_DRV_H_ */
