/******************************************************************************
 * $Revision: 423 $
 * $Date:: 2017-04-07 16:03:30 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************
 ** \file tcflash.c
 **
 ** A detailed description is available at
 ** @link TcflashGroup TCFLASH functions description @endlink
 **
 ** History:
 **   - 2014-12-01  0.01  HS  Initial version for Traveo
 *****************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "tcflash.h"

/**
 *****************************************************************************
 ** \addtogroup TcflashGroup
 *****************************************************************************/
//@{


/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/
#define TCFLASH_UNLOCK_LEY 				(0xCF61F1A5)

#define RES_ADDR_TO_THROW_DATA_ABORT    0xfffffff0 ///< Used as error return value for GetCommandAddress(), will generate a DataAbort if used by the calling function

#define CMD_ADDR0                    		0xaa8 ///< Offset address for command address 0
#define CMD_ADDR1							0x554 ///< Offset address for command address 1

#define CMD_WRITE_SEQ_VALUE_1                0xaa ///< 1st value in the Flash Write Sequence
#define CMD_WRITE_SEQ_VALUE_2                0x55 ///< 2nd value in the Flash Write Sequence
#define CMD_WRITE_SEQ_VALUE_3                0xa0 ///< 3rd value in the Flash Write Sequence
#define CMD_64BIT_WRITE_SEQ_VALUE_3          0xac ///< 3rd value in the Flash Write Sequence with 64bit data length

#define CMD_ERASE_SEQ_VALUE_1                0xaa ///< 1st value in the Flash Erase Sequence
#define CMD_ERASE_SEQ_VALUE_2                0x55 ///< 2nd value in the Flash Erase Sequence
#define CMD_ERASE_SEQ_VALUE_3                0x80 ///< 3rd value in the Flash Erase Sequence
#define CMD_ERASE_SEQ_VALUE_4                0xaa ///< 4th value in the Flash Erase Sequence
#define CMD_ERASE_SEQ_VALUE_5                0x55 ///< 5th value in the Flash Erase Sequence
#define CMD_ERASE_MACRO_SEQ_VALUE_6          0x10 ///< 6th value in the Flash Erase Sequence for Macro Erasing
#define CMD_ERASE_SECTOR_SEQ_VALUE_6         0x30 ///< 6th value in the Flash Erase Sequence for Sector Erasing
#define CMD_ERASE_MULTI_SECTOR_SEQ_VALUE_6   0xE0 ///< 6th value in the Flash Erase Sequence for Multiple Sector Erasing
#define CMD_ERASE_MULTI_SECTOR_SEQ_VALUE_7   0x30 ///< 7th value in the Flash Erase Sequence for Multiple Sector Erasing

#define MAKE_LARGE_SECTOR_CMD_BASE_ADDR(addr)   ((addr) & 0xffff0000) ///< Makes the base address for command address offset adding in a large sector
#define MAKE_SMALL_SECTOR_CMD_BASE_ADDR(addr)   ((addr) & 0xffffe000) ///< Makes the base address for command address offset adding in a small sector

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/

/**
 *****************************************************************************
 ** \brief Internal TCFLASH data.
 *****************************************************************************/

/**
 *****************************************************************************
 ** \brief Parameter for GetCommandAddress()
 *****************************************************************************/
typedef enum en_cmd_addr_type
{
    enCmdAddr0 = 0,
    enCmdAddr1
} en_cmd_addr_type_t;

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/
                                                                           
/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/
static boolean_t IsSmallSector(uint32_t u32Address);
static boolean_t IsLargeSector(uint32_t u32Address);
static boolean_t TcflashIsFlash(uint32_t u32Address);
static boolean_t IsFlashAxiAddress(uint32_t u32Address);
static uint32_t GetCommandAddress(uint32_t u32Address, en_cmd_addr_type_t enCmdAddrType);
static en_result_t TcflashWaitUntilRdy(un_tcfcfg0_fstat_t stcChecBits);
static boolean_t TcflashCanBeWritten(void);
static void TcflashUnlock(void);

/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/
/**
 *****************************************************************************
 ** \brief Erases a TCFLASH macro
 **
 ** Erases the TCFLASH macro that contains the specified address.
 ** Use with care as your remaining application may be deleted if it is not
 ** running from RAM. In most cases multiply calling Tcflash_SectorErase()
 ** might be the better decision.
 ** 
 ** \note Do not cancel the operation (e.g. reset, power-off), as it may leave the
 **       Flash description records in an undefined state, preventing any further
 **       access to the MCU
 **
 ** \param [in]  u32Address       The TCFLASH macro where this address belongs to
 **                               will be erased
 ** \param [in]  bBlocking        If TRUE, this function waits for completion of the command.
 ** 							  (wait for FLASH status is RDY or HANG)
 ** 							  If FALSE, return immediately.
 **
 ** \retval Ok                    TCFLASH macro has been erased successfully
 ** \retval Error                 TCFLASH macro erasing failed
 ** \retval ErrorInvalidMode      Write Access permission is not provided.
 ** \retval ErrorInvalidParameter - If u32Address does not belong to any TCFLASH macro
 **                               - If u32Address is not 32-bit aligned
 *****************************************************************************/
en_result_t Tcflash_MacroErase(uint32_t u32Address, boolean_t bBlocking)
{
    en_result_t         enResult;
    boolean_t           bCanBeWritten;
    volatile uint32_t * pu32CmdAddr0;
    volatile uint32_t * pu32CmdAddr1;
    un_tcfcfg0_fstat_t   unCheckBits;

    /* TCFLASH is ready and write enable? */
    bCanBeWritten = TcflashCanBeWritten();
    if (bCanBeWritten == FALSE)
    {
        return ErrorInvalidMode;
    }

    // Check if address belongs to Flash AXI port address space
    if (IsFlashAxiAddress(u32Address) == FALSE)
    {
        // If address belongs to Flash TCM port address space,
        // it is translated to AXI address and function proceeds
        if (IsFlashAxiAddress(MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address)) == TRUE)
        {
            u32Address = MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address);
        }
        // Address neither belongs to TCM nor AXI port of Flash
        else
        {
            return ErrorInvalidParameter;
        }
    }

    // Check 32-bit alignment of address
    if ((u32Address & 0x3) != 0)
    {
        return ErrorInvalidParameter;
    }

    // Retrieve the command addresses for the current target address
    pu32CmdAddr0 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr0);
    pu32CmdAddr1 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr1);

    // Flash macro erase command sequence
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_1;
    *pu32CmdAddr1 = CMD_ERASE_SEQ_VALUE_2;
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_3;
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_4;
    *pu32CmdAddr1 = CMD_ERASE_SEQ_VALUE_5;
    *pu32CmdAddr0 = CMD_ERASE_MACRO_SEQ_VALUE_6;

    // Check status
    if (bBlocking != FALSE)
    {
        /* wait until ready */
    	unCheckBits.u32Register = 0;
    	unCheckBits.stcField.u1CERS = 1;
        enResult = TcflashWaitUntilRdy(unCheckBits);
    }
    else
    {
        /* Do not wait */
        enResult = Ok;
    }

    // Check status
    return enResult;
}

/**
 *****************************************************************************
 ** \brief Erases a TCFLASH sector
 **
 ** Erases the TCFLASH sector that contains the specified address.
 ** 
 ** \param [in]  u32Address       The TCFLASH sector where this address belongs to
 **                               will be erased
 ** \param [in]  bBlocking        If TRUE, this function waits for completion of the command.
 ** 							  (wait for FLASH status is RDY or HANG)
 ** 							  If FALSE, return immediately.
 **
 ** \retval Ok                    Sector erasing successfully done.
 ** \retval Error                 TCFLASH erasing failed
 ** \retval ErrorInvalidMode      Write Access permission is not provided.
 ** \retval ErrorInvalidParameter - If u32Address does not belong to any TCFLASH macro
 **                               - If u32Address is not 32-bit aligned
 *****************************************************************************/
en_result_t Tcflash_SectorErase(uint32_t u32Address, boolean_t bBlocking)
{
    boolean_t           bCanBeWritten;
    en_result_t         enResult;
    volatile uint32_t * pu32CmdAddr0;
    volatile uint32_t * pu32CmdAddr1;
    un_tcfcfg0_fstat_t   unCheckBits;

    /* TCFLASH is ready and write enable? */
    bCanBeWritten = TcflashCanBeWritten();
    if (bCanBeWritten == FALSE)
    {
        return ErrorInvalidMode;
    }

    // Check if address belongs to Flash AXI port address space
    if (IsFlashAxiAddress(u32Address) == FALSE)
    {
        // If address belongs to Flash TCM port address space,
        // it is translated to AXI address and function proceeds
        if (IsFlashAxiAddress( MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address) ) == TRUE)
        {
            u32Address = MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address);
        }
        // Address neither belongs to TCM nor AXI port of Flash
        else
        {
            return ErrorInvalidParameter;
        }
    }
    
    // Check 32-bit alignment of address
    if ((u32Address & 0x3) != 0)
    {
        return ErrorInvalidParameter;
    }

    // Retrieve the command addresses for the current target address
    pu32CmdAddr0 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr0);
    pu32CmdAddr1 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr1);

    // Flash macro erase command sequence
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_1;
    *pu32CmdAddr1 = CMD_ERASE_SEQ_VALUE_2;
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_3;
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_4;
    *pu32CmdAddr1 = CMD_ERASE_SEQ_VALUE_5;
    // Access to target sector
    *((volatile uint32_t *) u32Address) = CMD_ERASE_SECTOR_SEQ_VALUE_6;

    // Check status
    if (bBlocking != FALSE)
    {
        /* wait until ready */
    	unCheckBits.u32Register = 0;
    	unCheckBits.stcField.u1SERS = 1;
        enResult = TcflashWaitUntilRdy(unCheckBits);
    }
    else
    {
        /* Do not wait */
        enResult = Ok;
    }

    // Check status
    return enResult;
}


/**
 *****************************************************************************
 ** \brief Erases MULTIPLE TCFLASH sector
 **
 ** Erases the TCFLASH sector that contains the specified address.
 **
 ** \param [in]  au32Address      Array of The TCFLASH sector address.
 ** \param [in]  u8SectorCnt      # of The TCFLASH sector address.
 ** \param [in]  bBlocking        If TRUE, this function waits for completion of the command.
 ** 							  (wait for FLASH status is RDY or HANG)
 ** 							  If FALSE, return immediately.
 **
 ** \retval Ok                    Sector erasing successfully done.
 ** \retval Error                 TCFLASH erasing failed
 ** \retval ErrorInvalidMode      Write Access permission is not provided.
 ** \retval ErrorInvalidParameter - If u32Address does not belong to any TCFLASH macro
 **                               - If u32Address is not 32-bit aligned
 *****************************************************************************/
en_result_t Tcflash_MultipleSectorErase(uint32_t * au32Address, uint8_t u8SectorCnt, boolean_t bBlocking)
{
    boolean_t           bCanBeWritten;
    en_result_t         enResult;
    uint8_t				u8Itr;
    uint32_t			u32Address;
    volatile uint32_t * pu32CmdAddr0;
    volatile uint32_t * pu32CmdAddr1;
    un_tcfcfg0_fstat_t   unCheckBits;

    /* TCFLASH is ready and write enable? */
    bCanBeWritten = TcflashCanBeWritten();
    if (bCanBeWritten == FALSE)
    {
        return ErrorInvalidMode;
    }

    // loop for parameter check
    for (u8Itr = 0; u8Itr < u8SectorCnt; u8Itr++)
    {
        u32Address = au32Address[u8Itr];
    	// Check if address belongs to Flash AXI port address space
    	if (IsFlashAxiAddress(u32Address) == FALSE)
    	{
    		// If address belongs to Flash TCM port address space,
    		// it is translated to AXI address and function proceeds
    		if (IsFlashAxiAddress( MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address) ) == TRUE)
    		{
    			u32Address = MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address);
    		}
    		// Address neither belongs to TCM nor AXI port of Flash
    		else
    		{
    			return ErrorInvalidParameter;
    		}
    	}
        // Check 32-bit alignment of address
        if ((u32Address & 0x3) != 0)
        {
            return ErrorInvalidParameter;
        }

        au32Address[u8Itr] = u32Address;
    }

    // Retrieve the command addresses for the current target address
    pu32CmdAddr0 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr0);
    pu32CmdAddr1 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr1);
    
    // Flash macro erase command sequence
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_1;
    *pu32CmdAddr1 = CMD_ERASE_SEQ_VALUE_2;
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_3;
    *pu32CmdAddr0 = CMD_ERASE_SEQ_VALUE_4;
    *pu32CmdAddr1 = CMD_ERASE_SEQ_VALUE_5;

    // loop for issuing the command
    for (u8Itr = 0; u8Itr < u8SectorCnt - 1; u8Itr++)
    {
        u32Address = au32Address[u8Itr];

        // Access to target sector
        *((volatile uint32_t *) u32Address) = CMD_ERASE_MULTI_SECTOR_SEQ_VALUE_6;
    }

    // last sector
    u32Address = au32Address[u8SectorCnt - 1];
    *((volatile uint32_t *) u32Address) = CMD_ERASE_MULTI_SECTOR_SEQ_VALUE_7;

    // Check status
    if (bBlocking != FALSE)
    {
        /* wait until ready */
    	unCheckBits.u32Register = 0;
    	unCheckBits.stcField.u1SERS = 1;
        enResult = TcflashWaitUntilRdy(unCheckBits);
    }
    else
    {
        /* Do not wait */
        enResult = Ok;
    }

    // Check status
    return enResult;
}

/**
 *****************************************************************************
 ** \brief Writes a 32-bit word to TCFLASH
 **
 ** Writes a 32-bit value to the TCFLASH target address.
 **
 ** \param [in]  u32Address       The TCFLASH target address to be written
 ** \param [in]  u32Data          The data that shall be written
 ** \param [in]  bBlocking        If TRUE, this function waits for completion of the command.
 ** 							  (wait for FLASH status is RDY or HANG)
 ** 							  If FALSE, return immediately.
 **
 ** \retval Ok                    32-bit word has been written successfully
 ** \retval Error                 TCFLASH writing failed
 ** \retval ErrorInvalidMode      Write Access permission is not provided.
 ** \retval ErrorInvalidParameter - If u32Address does not belong to any TCFLASH macro
 **                               - If u32Address is not 32-bit aligned
 *****************************************************************************/
en_result_t Tcflash_Write32(uint32_t u32Address, uint32_t u32Data, boolean_t bBlocking)
{
    boolean_t           bCanBeWritten;
    en_result_t         enResult;
    volatile uint32_t * pu32CmdAddr0;
    volatile uint32_t * pu32CmdAddr1;
    un_tcfcfg0_fstat_t   unCheckBits;

    /* TCFLASH is ready and write enable? */
    bCanBeWritten = TcflashCanBeWritten();
    if (bCanBeWritten == FALSE)
    {
        return ErrorInvalidMode;
    }

    // Check if address belongs to Flash AXI port address space
    if (IsFlashAxiAddress(u32Address) == FALSE)
    {
        // If address belongs to Flash TCM port address space,
        // it is translated to AXI address and function proceeds
        if (IsFlashAxiAddress(MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address)) == TRUE)
        {
            u32Address = MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address);
        }
        // Address neither belongs to TCM nor AXI port of Flash
        else
        {
            return ErrorInvalidParameter;
        }
    }

    // Check 32-bit alignment of address
    if ((u32Address & 0x3) != 0)
    {
        return ErrorInvalidParameter;
    }

    // Retrieve the command addresses for the current target address
    pu32CmdAddr0 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr0);
    pu32CmdAddr1 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr1);

    // Flash write command sequence  -  (1st access, lower 16-bit will actually be written to Flash)
    *pu32CmdAddr0 = CMD_WRITE_SEQ_VALUE_1;
    *pu32CmdAddr1 = CMD_WRITE_SEQ_VALUE_2;
    *pu32CmdAddr0 = CMD_WRITE_SEQ_VALUE_3;
    // Access to target address
    *((volatile uint32_t *) u32Address) = u32Data;

    if (bBlocking != FALSE)
    {
        /* wait until ready */
    	unCheckBits.u32Register = 0;
    	unCheckBits.stcField.u1PGMS = 1;
        enResult = TcflashWaitUntilRdy(unCheckBits);
    }
    else
    {
        /* Do not wait */
        enResult = Ok;
    }

    // Check status
    return enResult;
}

/**
 *****************************************************************************
 ** \brief Writes a 32-bit word to TCFLASH
 **
 ** Writes a 32-bit value to the TCFLASH target address.
 **
 ** \param [in]  u32Address       The TCFLASH target address to be written
 ** \param [in]  u32Data          The data that shall be written
 ** \param [in]  bBlocking        If TRUE, this function waits for completion of the command.
 ** 							  (wait for FLASH status is RDY or HANG)
 ** 							  If FALSE, return immediately.
 **
 ** \retval Ok                    32-bit word has been written successfully
 ** \retval Error                 TCFLASH writing failed
 ** \retval ErrorInvalidMode      Write Access permission is not provided.
 ** \retval ErrorInvalidParameter - If u32Address does not belong to any TCFLASH macro
 **                               - If u32Address is not 32-bit aligned
 *****************************************************************************/
uint32_t Tcflash_Read32(uint32_t u32Address, boolean_t bBlocking)
{
    boolean_t           bCanBeWritten;
    en_result_t         enResult;
    uint32_t u32Data;
    un_tcfcfg0_fstat_t   unCheckBits;

    /* TCFLASH is ready and write enable? */
    bCanBeWritten = TcflashCanBeWritten();
    if (bCanBeWritten == FALSE)
    {
        return ErrorInvalidMode;
    }

    // Check if address belongs to Flash AXI port address space
    if (IsFlashAxiAddress(u32Address) == FALSE)
    {
        // If address belongs to Flash TCM port address space,
        // it is translated to AXI address and function proceeds
        if (IsFlashAxiAddress(MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address)) == TRUE)
        {
            u32Address = MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address);
        }
        // Address neither belongs to TCM nor AXI port of Flash
        else
        {
            return ErrorInvalidParameter;
        }
    }

    // Check 32-bit alignment of address
    if ((u32Address & 0x3) != 0)
    {
        return ErrorInvalidParameter;
    }

   
    // Access to target address
    u32Data = *((volatile uint32_t *) u32Address) ;

    if (bBlocking != FALSE)
    {
        /* wait until ready */
    	unCheckBits.u32Register = 0;
    	unCheckBits.stcField.u1PGMS = 1;
        enResult = TcflashWaitUntilRdy(unCheckBits);
    }
    else
    {
        /* Do not wait */
        return u32Data;
    }

    // Check status
    if (enResult==Ok)
    {
	return u32Data;
	
    }
	
}


/**
 *****************************************************************************
 ** \brief Writes a 64-bit word to TCFLASH
 **
 ** Writes a 64-bit value to the TCFLASH target address.
 **
 ** \param [in]  u32Address       The TCFLASH target address to be written
 ** \param [in]  u64Data          The data that shall be written
 ** \param [in]  bBlocking        If TRUE, this function waits for completion of the command.
 ** 							  (wait for FLASH status is RDY or HANG)
 ** 							  If FALSE, return immediately.
 **
 ** \retval Ok                    32-bit word has been written successfully
 ** \retval Error                 TCFLASH writing failed
 ** \retval ErrorInvalidMode      Write Access permission is not provided.
 ** \retval ErrorInvalidParameter - If u32Address does not belong to any TCFLASH macro
 **                               - If u32Address is not 64-bit aligned
 *****************************************************************************/
en_result_t Tcflash_Write64(uint32_t u32Address, uint64_t u64Data, boolean_t bBlocking)
{
    boolean_t           bCanBeWritten;
    en_result_t         enResult;
    volatile uint32_t * pu32CmdAddr0;
    volatile uint32_t * pu32CmdAddr1;
    un_tcfcfg0_fstat_t   unCheckBits;

    /* TCFLASH is ready and write enable? */
    bCanBeWritten = TcflashCanBeWritten();
    if (bCanBeWritten == FALSE)
    {
        return ErrorInvalidMode;
    }

    // Check if address belongs to Flash AXI port address space
    if (IsFlashAxiAddress(u32Address) == FALSE)
    {
        // If address belongs to Flash TCM port address space,
        // it is translated to AXI address and function proceeds
        if (IsFlashAxiAddress(MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address)) == TRUE)
        {
            u32Address = MCU_FLASH_ADDRESS_TCM2AXI_PRIVATE(u32Address);
        }
        // Address neither belongs to TCM nor AXI port of Flash
        else
        {
            return ErrorInvalidParameter;
        }
    }

    // Check 64-bit alignment of address
    if ((u32Address & 0x7) != 0)
    {
        return ErrorInvalidParameter;
    }

    // Retrieve the command addresses for the current target address
    pu32CmdAddr0 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr0);
    pu32CmdAddr1 = (uint32_t *) GetCommandAddress(u32Address, enCmdAddr1);

    // Flash write command sequence
    *pu32CmdAddr0 = CMD_WRITE_SEQ_VALUE_1;
    *pu32CmdAddr1 = CMD_WRITE_SEQ_VALUE_2;
    *pu32CmdAddr0 = CMD_64BIT_WRITE_SEQ_VALUE_3;
    // Access to target address (lower 32bit)
    *((volatile uint32_t *) u32Address) = (uint32_t)u64Data;
    // Access to target address (upper 32bit)
    *((volatile uint32_t *) u32Address) = (uint32_t)(u64Data >> 32);

    if (bBlocking != FALSE)
    {
        /* wait until ready */
    	unCheckBits.u32Register = 0;
    	unCheckBits.stcField.u1PGMS = 1;
        enResult = TcflashWaitUntilRdy(unCheckBits);
    }
    else
    {
        /* Do not wait */
        enResult = Ok;
    }

    // Check status
    return enResult;
}


/**
 *****************************************************************************
 ** \brief Issue macro reset
 **
 ** \retval ErrorInvalidMode    If following conditions are met:
 **                                 - Write access is disabled.
 **                                 - Flash erasing has been suspended.
 ** \retval Ok                  successfully done.
 *****************************************************************************/
en_result_t Tcflash_Reset(void)
{
	un_tcfcfg0_fstat_t unStatus;
	boolean_t bCanBeWritten;

	/* ---- Parameter and Condition Check ---- */
    /* Check CPU mode. */
    if (FALSE == Cpu_CpuIsInPrivilegedMode())
    {
        return ErrorAccessRights;
    }

    /* Check if the write is enabled */
    bCanBeWritten = TcflashCanBeWritten();
    if (bCanBeWritten == FALSE)
    {
        return ErrorInvalidMode;
    }

    /* ---- Do operations ---- */
    /* Write unlock before each write access to configuration register. */
    TcflashUnlock();
    /* Software reset */
    TCFCFG0_FCFGR_SWFRST = 1;

    /* Wait until ready */
    do{
    	unStatus = Tcflash_GetStatus();
    }while (unStatus.stcField.u1RDY != 0);

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Check if TCFLASH can be written.
 **
 ** \retval TRUE  TCFLASH macro is ready to write.
 ** \retval FALSE TCFLASH macro is not ready to write.
 *****************************************************************************/
static boolean_t TcflashCanBeWritten(void)
{
    boolean_t bCanBeWritten = TRUE;
    un_tcfcfg0_fstat_t stcStatus;

    /* Write enable? */
    if (TCFCFG0_FCFGR_WE == 0)
    {
        bCanBeWritten = FALSE;
    }
    else
    {
        /* Check if flash status is ready */
    	stcStatus = Tcflash_GetStatus();
        if (stcStatus.stcField.u1RDY == 0)
        {
            bCanBeWritten = FALSE;
        }
    }

    return bCanBeWritten;
}

/**
 *****************************************************************************
 ** \brief Wait until TCFLASH macro is ready for new commands
 **
 ** \retval Ok    TCFLASH macro is ready to accept new commands.
 ** \retval Error TCFLASH macro is hanging.
 **               If hanging, this function issue read/reset command to
 **               clear hanging status.
 *****************************************************************************/
static en_result_t TcflashWaitUntilRdy(un_tcfcfg0_fstat_t stcChecBits)
{
    en_result_t enResult = Ok;
    un_tcfcfg0_fstat_t stcStatus;

    /* wait until ready or hang */
    do{
    	stcStatus = Tcflash_GetStatus();
        /* When wait for ready, watchdog handling may be needed. */
    }while ((stcChecBits.u32Register & stcStatus.u32Register) != 0 && stcStatus.stcField.u1HANG == 0);

    /* Check if flash macro is hanging */
    if (stcStatus.stcField.u1HANG == 1)
    {
        /* Issue macro reset */
        (void)Tcflash_Reset();
        enResult = Error;
    }

    return enResult;
}


/**
 *****************************************************************************
 ** \brief Checks if target address belongs to a small sector in AXI address space
 **
 ** \param [in]  u32Address   Target address to be examined
 **
 ** \retval TRUE              u32Address belongs to a small TCFLASH sector
 ** \retval FALSE             u32Address does not belong to a small TCFLASH sector
 *****************************************************************************/
static boolean_t IsSmallSector(uint32_t u32Address)
{
    if((TCFLASH_AXI_PORT_SMALL_BASE <= u32Address) && (u32Address < (TCFLASH_AXI_PORT_SMALL_BASE + TCFLASH_TOTAL_SIZE_SMALL_SECTORS)))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/**
 *****************************************************************************
 ** \brief Checks if target address belongs to a large sector in AXI address space
 **
 ** \param [in]  u32Address   Target address to be examined
 **
 ** \retval TRUE              u32Address belongs to a large TCFLASH sector
 ** \retval FALSE             u32Address does not belong to a large TCFLASH sector
 *****************************************************************************/
static boolean_t IsLargeSector(uint32_t u32Address)
{
    if((TCFLASH_AXI_PORT_LARGE_BASE <= u32Address) && (u32Address < (TCFLASH_AXI_PORT_LARGE_BASE + TCFLASH_TOTAL_SIZE_LARGE_SECTORS)))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/**
 *****************************************************************************
 ** \brief Checks if target address belongs to TCFLASH macro A AXI address space
 **
 ** \param [in]  u32Address   Target address to be examined
 **
 ** \retval TRUE              u32Address belongs to TCFLASH
 ** \retval FALSE             u32Address does not belong to TCFLASH
 *****************************************************************************/
static boolean_t TcflashIsFlash(uint32_t u32Address)
{
    if (IsLargeSector(u32Address))
    {
        return TRUE;
    }
    else if (IsSmallSector(u32Address) && ((TCFLASH_AXI_PORT_SMALL_BASE <= u32Address) &&
    		(u32Address < (TCFLASH_AXI_PORT_SMALL_BASE + TCFLASH_TOTAL_SIZE_SMALL_SECTORS))))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}


/**
 *****************************************************************************
 ** \brief Checks if target address belongs to TCFLASH AXI address space
 **
 ** \param [in]  u32Address   Target address to be examined
 **
 ** \retval TRUE              u32Address belongs to TCFLASH AXI address space
 ** \retval FALSE             u32Address does not belong to TCFLASH AXI address space
 *****************************************************************************/
static boolean_t IsFlashAxiAddress(uint32_t u32Address)
{
    if (TcflashIsFlash(u32Address) == TRUE)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}


/**
 *****************************************************************************
 ** \brief Returns a command address
 **
 ** The command sequences to trigger any Flash action consist of two different
 ** command addresses.
 **
 ** \pre Ensure that u32Address belongs to TCFLASH AXI address space at all
 **      before calling this function
 **
 ** \param [in]  u32Address    Target address for which the corresponding command
 **                            address shall be calculated
 ** \param [in]  enCmdAddrType Decides which command address (0 or 1) shall be returned
 **
 ** \return Requested command address (or RES_ADDR_TO_THROW_DATA_ABORT if u32Address is not valid)
 *****************************************************************************/
static uint32_t GetCommandAddress(uint32_t u32Address, en_cmd_addr_type_t enCmdAddrType)
{
    uint32_t u32CmdAddr = 0;

    if (IsSmallSector(u32Address) == TRUE)
    {
        u32CmdAddr = MAKE_SMALL_SECTOR_CMD_BASE_ADDR(u32Address) + (enCmdAddrType == enCmdAddr0 ? CMD_ADDR0 : CMD_ADDR1);
    }
    else
    {
        if (TcflashIsFlash(u32Address) == TRUE)
        {
            u32CmdAddr = MAKE_LARGE_SECTOR_CMD_BASE_ADDR(u32Address) + (enCmdAddrType == enCmdAddr0 ? CMD_ADDR0 : CMD_ADDR1);
        }
        else
        {
            u32CmdAddr = RES_ADDR_TO_THROW_DATA_ABORT; // should not be reached
        }
    }

    return u32CmdAddr;
}

/**
 *****************************************************************************
 ** \brief Get status of the TCFLASH memory
 **
 ** \retval un_tcfcfg_fstat_t	TCFLASH status bits.
 *****************************************************************************/
un_tcfcfg0_fstat_t Tcflash_GetStatus(void)
{
	un_tcfcfg0_fstat_t  stcStatus;

    /* Read status register */
    stcStatus.u32Register = TCFCFG0_FSTAT;

    return stcStatus;
}

/**
 *****************************************************************************
 ** \brief Enables write access to TCFLASH.
 **
 ** \pre Must be run from privileged mode.
 **
 ** \retval Ok                  Write access enabled.
 ** \retval ErrorAccessRights   Call of function was not done in privileged mode.
 ** \retval ErrorInvalidMode    Can not get write permission.
 *****************************************************************************/
en_result_t Tcflash_EnableWriteAccess(void)
{
    en_result_t enResult = Ok;

    /* ---- Parameter and Condition Check ---- */
    /* Check CPU mode. */
    if (FALSE == Cpu_CpuIsInPrivilegedMode())
    {
        enResult = ErrorAccessRights;
    }else
    {
        /* ---- Do operations ---- */
        /* Disable IRQ */
        IRQ_DISABLE_LOCAL();

        /* Check if can get the write permission */
        if (WFCFG_WARBR_WERSTS != 1)
        {
            enResult = ErrorInvalidMode;
        }
        else
        {
            /* Write unlock before each write access to configuration register. */
        	TcflashUnlock();
            /* Enabled writing to TCFLASH */
        	TCFCFG0_FCFGR_WE = 1;
        }

        /* Restore IRQ state */
        IRQ_RESTORE();
    }

    return enResult;
}

/**
 *****************************************************************************
 ** \brief Disables write access to TCFLASH.
 **
 ** \pre Must be run from privileged mode.
 **
 ** \retval Ok                Write access disabled.
 ** \retval ErrorAccessRights Call of function was not done in privileged mode.
 *****************************************************************************/
en_result_t Tcflash_DisableWriteAccess(void)
{
    en_result_t enResult = Ok;

    /* ---- Parameter and Condition Check ---- */
    /* Check CPU mode. */
    if (FALSE == Cpu_CpuIsInPrivilegedMode())
    {
        enResult = ErrorAccessRights;
    }
    else
    {
        /* ---- Do operations ---- */
        /* Disable IRQ for protected sequence */
        IRQ_DISABLE_LOCAL();

        /* Write unlock before each write access to configuration register. */
        TcflashUnlock();
        /* Work Flash write disable. */
        TCFCFG0_FCFGR_WE = 0;

        /* Restore IRQ state */
        IRQ_RESTORE();
    }

    return enResult;
}

/**
 *****************************************************************************
 ** \brief Unlocks the TCFLASH configuration registers for one write access.
 **
 ** \return None
 *****************************************************************************/
static void TcflashUnlock(void)
{
	TCFCFG0_FCPROTKEY = TCFLASH_UNLOCK_LEY;
}

//@} // TcflashGroup

//#endif //(PDL_PERIPHERAL_TCFLASH_ACTIVE)

/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/
