/*
*
* Copyright (c) 2022 Texas Instruments Incorporated
*
* All rights reserved not granted herein.
*
* Limited License.
*
* Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive
* license under copyrights and patents it now or hereafter owns or controls to make,
* have made, use, import, offer to sell and sell ("Utilize") this software subject to the
* terms herein.  With respect to the foregoing patent license, such license is granted
* solely to the extent that any such patent is necessary to Utilize the software alone.
* The patent license shall not apply to any combinations which include this software,
* other than combinations with devices manufactured by or for TI ("TI Devices").
* No hardware patent is licensed hereunder.
*
* Redistributions must preserve existing copyright notices and reproduce this license
* (including the above copyright notice and the disclaimer and (if applicable) source
* code license limitations below) in the documentation and/or other materials provided
* with the distribution
*
* Redistribution and use in binary form, without modification, are permitted provided
* that the following conditions are met:
*
* No reverse engineering, decompilation, or disassembly of this software is
* permitted with respect to any software provided in binary form.
*
* any redistribution and use are licensed by TI for use only with TI Devices.
*
* Nothing shall obligate TI to provide you with source code for the software
* licensed and provided to you in object code.
*
* If software source code is provided to you, modification and redistribution of the
* source code are permitted provided that the following conditions are met:
*
* any redistribution and use of the source code, including any resulting derivative
* works, are licensed by TI for use only with TI Devices.
*
* any redistribution and use of any object code compiled from the source code
* and any resulting derivative works, are licensed by TI for use only with TI Devices.
*
* Neither the name of Texas Instruments Incorporated nor the names of its suppliers
*
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* DISCLAIMER.
*
* THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
 *  \file     Fls_Brd_Nor_Qspi.c
 *
 *  This file contains FLS MCAL driver internal functions for Board Nor QSPI
 *
 */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include "stdint.h"
#include "string.h"
#include "Fls_Brd_Nor.h"
#include "Fee_Cbk.h"
#include "hw_types.h"
/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
#define QSPI_NOR_SR_WIP             (1U << 0U)
#define QSPI_NOR_SR_WEL             (1U << 1U)
#define FLASH_QSPI_ID_CODE_SIZE_MAX (8U)
/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                 Internal Function Declarations                             */
/* ========================================================================== */

static Std_ReturnType Nor_QspiCmdRead(QSPI_Handle handle, uint8 cmd, 
									uint32 cmdAddr, uint8 *rxBuf, uint32 rxLen);
static Std_ReturnType Nor_QspiCmdWrite(QSPI_Handle handle, uint8 cmd, 
									uint32 cmdAddr, uint8 *txBuf, uint32 txLen);
static Std_ReturnType Nor_QspiWriteEnableLatched(QSPI_Handle handle, uint32 timeOut);
static Std_ReturnType Nor_QspiWaitReady(QSPI_Handle handle, uint32 timeOut);
static Std_ReturnType Nor_QspiQuadReadEnable(void);
static Std_ReturnType Nor_QspiReadId(void);

static Std_ReturnType Fls_norOpen(void);
static Std_ReturnType Fls_norWrite(uint32 actualChunkSize);
static Std_ReturnType Fls_norErase(uint32 actualChunkSize);
static Std_ReturnType Fls_norRead(uint32 actualChunkSize);
static boolean Fls_VerifyData_priv(const uint8 *expData,
                const uint8 *rxData,
                uint32 length);
static Std_ReturnType Fls_norCompare(uint32 actualChunkSize);
static Std_ReturnType Fls_norBlankCheck(uint32 actualChunkSize);				
								
/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */


#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"

/**
 *  \Function Name: Nor_QspiCmdRead
 *
 *  This function perform read operation for QSPI protocol by passing command 
 *  and will get corresponding data
 *  
 *
 */

static Std_ReturnType Nor_QspiCmdRead(QSPI_Handle handle, uint8 cmd, 
									uint32 cmdAddr, uint8 *rxBuf, uint32 rxLen)
{
    Std_ReturnType retVal = E_OK;
    QSPI_CmdParams rdParams;
	
    if (Fls_Qspi_ParamsInit(&rdParams) == E_OK)
	{
		rdParams.cmd       = cmd;
		rdParams.cmdAddr   = cmdAddr;
		rdParams.rxDataBuf = rxBuf;
		rdParams.txDataBuf  = NULL;
		rdParams.DataLen = rxLen;
		
		if (Fls_Qspi_ReadCmd(handle, &rdParams) == E_OK)
		{
			retVal = E_OK;
		}
		else
		{
			retVal = E_NOT_OK;
		}
	}
	else
	{
		retVal = E_NOT_OK;
	}

    return retVal;
}

/**
 *  \Function Name: Nor_QspiCmdWrite
 *
 *  This function perform write operation for QSPI protocol through the passing 
 *  Command
 *
 */

static Std_ReturnType Nor_QspiCmdWrite(QSPI_Handle handle, uint8 cmd, 
									uint32 cmdAddr, uint8 *txBuf, uint32 txLen)
{
    Std_ReturnType retVal = E_OK;

    QSPI_CmdParams wrParams;
    if (Fls_Qspi_ParamsInit(&wrParams) == E_OK)
	{
		wrParams.cmd        = cmd;
		wrParams.cmdAddr    = cmdAddr;
		wrParams.txDataBuf  = txBuf;
		wrParams.rxDataBuf = NULL;
		wrParams.DataLen  = txLen;
		
		if (Fls_Qspi_WriteCmd(handle, &wrParams) == E_OK)
		{
			retVal = E_OK;
		}
		else
		{
			retVal = E_NOT_OK;
		}
	}
	else
	{
		retVal = E_NOT_OK;
	}

    return retVal;
}

/**
 *  \Function Name: Nor_QspiWriteEnableLatched
 *
 *  This function enable the latch for write opearation. 
 *
 */

static Std_ReturnType Nor_QspiWriteEnableLatched(QSPI_Handle handle, uint32 timeOut)
{
    Std_ReturnType retVal = E_OK;
    uint8 readStatus = 0U;
    uint8 cmd = 0U;

    cmd = NOR_CMD_RDSR1;

    do
    {
        retVal = Nor_QspiCmdRead(handle, cmd, QSPI_CMD_INVALID_ADDR, &readStatus, 1);
        if(retVal != E_OK)
        {
            break;
        }
        if((readStatus & QSPI_NOR_SR_WEL) != 0)
        {
            break;
        }
        timeOut--;
        if(timeOut == 0)
        {
            retVal = E_NOT_OK;
            break;
        }
    } while(1);

    if((readStatus & QSPI_NOR_SR_WEL) != 0)
    {
        retVal = E_OK;
    }
    else
    {
        retVal = E_NOT_OK;
    }

    return retVal;
}

/**
 *  \Function Name: Nor_QspiWaitReady
 *
 *  This function will perform delay opearation for QSPI read untill
 *  will get read status. 
 *
 */

static Std_ReturnType Nor_QspiWaitReady(QSPI_Handle handle, uint32 timeOut)
{
    Std_ReturnType retVal = E_OK;
    uint8 readStatus = 0U;
    uint8 cmd = 0U;

    cmd = NOR_CMD_RDSR1;

    do
    {
        retVal = Nor_QspiCmdRead(handle, cmd, QSPI_CMD_INVALID_ADDR, &readStatus, 1);
        if(retVal != E_OK)
        {
            break;
        }
        if((readStatus & QSPI_NOR_SR_WIP) == 0)
        {
            break;
        }
        timeOut--;
        if(timeOut == 0)
        {
            retVal = E_NOT_OK;
            break;
        }
    } while(1);

    if((readStatus & QSPI_NOR_SR_WIP) == 0)
    {
        retVal = E_OK;
    }
    else
    {
        retVal = E_NOT_OK;
    }

    return retVal;
}

/**
 *  \Function Name: Nor_QspiQuadReadEnable
 *
 *  This function Enable QSPI Read operation.
 *
 */

static Std_ReturnType Nor_QspiQuadReadEnable(void)
{
    Std_ReturnType retVal = E_OK;
    uint8 readreg1 = 0U;
    uint8 readreg2 = 0U;
	
	if (Nor_QspiCmdWrite(Fls_DrvObj.spiHandle, NOR_CMD_WREN, QSPI_CMD_INVALID_ADDR, NULL, 0) == E_OK)
    {
		if (Nor_QspiWriteEnableLatched(Fls_DrvObj.spiHandle,NOR_WRR_WRITE_TIMEOUT) == E_OK)
		{
			if(Nor_QspiCmdRead(Fls_DrvObj.spiHandle, NOR_CMD_RDSR1, QSPI_CMD_INVALID_ADDR, &readreg1, 1) == E_OK)
			{
				if (Nor_QspiCmdRead(Fls_DrvObj.spiHandle, NOR_CMD_RDSR2, QSPI_CMD_INVALID_ADDR, &readreg2, 1) == E_OK)
				{
					retVal = E_OK;
				}	
			}
			else
			{
				retVal = E_NOT_OK;
			}
		}
		else
		{
			retVal = E_NOT_OK;
		}
    }
	else
	{
		retVal = E_NOT_OK;
	}
	if 	(retVal == E_OK)
	{
		readreg2 |= 0x2;
		uint16 regdata = 0;
		regdata |= readreg2;
		regdata = (regdata << 8) | readreg1;
						
		if(Nor_QspiCmdWrite(Fls_DrvObj.spiHandle, NOR_CMD_WRSR, 
						QSPI_CMD_INVALID_ADDR, (uint8 *)&regdata, 2) == E_OK)
		{
			if(Nor_QspiWaitReady(Fls_DrvObj.spiHandle, 
												NOR_PAGE_PROG_TIMEOUT) == E_OK)
			{
				retVal = E_OK;
			}
			else
			{
				retVal = E_NOT_OK;
			}
		}
		else
		{
			retVal = E_NOT_OK;
		}
	}			
    return retVal;
}

/**
 *  \Function Name: Nor_QspiReadId
 *
 *  This function check the device id and manufacture id for external flash.
 *
 */

static Std_ReturnType Nor_QspiReadId(void)
{
    Std_ReturnType retVal = E_OK;
    uint32 manfID, devID;
    uint8 idCode[FLASH_QSPI_ID_CODE_SIZE_MAX];
    uint8 cmd = QSPI_CMD_INVALID_OPCODE;
    uint32 cmdAddr = QSPI_CMD_INVALID_ADDR;
    uint32 numRdIdBytes = 0U;

    cmd = NOR_CMD_RDID;
    numRdIdBytes = NOR_RDID_NUM_BYTES;

    retVal = Nor_QspiCmdRead(Fls_DrvObj.spiHandle, cmd, cmdAddr, idCode, numRdIdBytes);

    if(retVal == E_OK)
    {
        manfID = (uint32)idCode[0];
        devID = ((uint32)idCode[1] << 8) | ((uint32)idCode[2]);
        if ((manfID != NOR_MANF_ID) && (devID != NOR_DEVICE_ID))
        {
            retVal = E_NOT_OK;
        }

    }

    return retVal;
}

/**
 *  \Function Name: Fls_norOpen
 *
 *  This function invokes Fls_QspiOpen and checks the device and manufacture id
 *
 */

static Std_ReturnType Fls_norOpen(void)
{
    Std_ReturnType retVal = E_OK;
	QSPI_Handle handle;
	
	Fls_DrvObj.spiHandle = Fls_QspiOpen(0U);
    handle = Fls_DrvObj.spiHandle;
	QSPI_Object  *object = ((QSPI_Config *)handle)->object;
	
    if(Fls_DrvObj.spiHandle == NULL)
    {
        retVal = E_NOT_OK;
    }
    if(retVal == E_OK)
    {
        uint8 cmd;
        /* Reset the Flash */
        cmd = NOR_CMD_RSTEN;
		
		if (Nor_QspiCmdWrite(Fls_DrvObj.spiHandle, cmd, QSPI_CMD_INVALID_ADDR, NULL, 0) == E_OK )
		{
			cmd = NOR_CMD_RST;
			if (Nor_QspiCmdWrite(Fls_DrvObj.spiHandle, cmd, QSPI_CMD_INVALID_ADDR, NULL, 0) == E_OK)
			{
				if (Nor_QspiWaitReady(Fls_DrvObj.spiHandle,NOR_WRR_WRITE_TIMEOUT) == E_OK)
				{
					object->writeCmd = NOR_PAGE_PROG;
					object->readCmd = NOR_CMD_QUAD_READ;
					object->numAddrBytes = NOR_ADDR_NUM_BYTES;
					object->numDummyBits = NOR_QUAD_READ_DUMMY_CYCLE;
					if (Nor_QspiQuadReadEnable() == E_OK)
					{
						if(Nor_QspiReadId() == E_OK)
						{
							retVal = E_OK;
						}
						else
						{
							retVal = E_NOT_OK;
						}
					}
					else
					{
						retVal = E_NOT_OK;
					}
					
				}
				else
				{
					retVal = E_NOT_OK;
				}
			}
			else
			{
				retVal = E_NOT_OK;
			}
		}
		else 
		{
			retVal = E_NOT_OK; 
		}
		
    }
    return (retVal);
}

/**
 *  \Function Name: Fls_hwUnitInit
 *
 *  This function initialize Hardware 
 *
 */

Std_ReturnType Fls_hwUnitInit(void)
{
    Std_ReturnType retVal;
    QSPI_Handle handle = NULL_PTR;
	
    (void)Fls_QspiHwInit();
	
	retVal = Fls_norOpen();
	
	handle = Fls_DrvObj.spiHandle;
	
    if (handle != NULL_PTR && retVal != E_NOT_OK)
    {
        retVal = E_OK;
    }
    else
    {
        retVal = E_NOT_OK;
    }
    return retVal;
}

/**
 *  \Function Name: Fls_hwUnitInit
 *
 *  This function invoke Det_ReportTransientFault.this will report DET. 
 *   
 *
 */

static void ReportFlsError(Fls_JobType job)
{
    switch(job) {
        case FLS_JOB_COMPARE:
			(void) Det_ReportTransientFault(FLS_MODULE_ID, FLS_INSTANCE_ID, FLS_SID_COMPARE, FLS_E_COMPARE_FAILED);
            break;
        case FLS_JOB_ERASE:
			(void) Det_ReportTransientFault(FLS_MODULE_ID, FLS_INSTANCE_ID, FLS_SID_ERASE, FLS_E_ERASE_FAILED);
            break;
        case FLS_JOB_READ:
			(void) Det_ReportTransientFault(FLS_MODULE_ID, FLS_INSTANCE_ID, FLS_SID_READ, FLS_E_READ_FAILED);
            break;
        case FLS_JOB_WRITE:
			(void) Det_ReportTransientFault(FLS_MODULE_ID, FLS_INSTANCE_ID, FLS_SID_WRITE, FLS_E_WRITE_FAILED);
            break;
        default:
            break;
    }
	Fls_DrvObj.jobResultType = MEMIF_JOB_FAILED;
	Fls_DrvObj.status = MEMIF_IDLE;
}

/**
 *  \Function Name: processJobs
 *
 *  This function invoke Fls_norCompare,Fls_norErase,Fls_norRead,Fls_norWrite
 *  and Fls_norBlankCheck function. it will perform any one function based on jobtype 
 *   
 *
 */

void processJobs(Fls_JobType job)
{
    uint32 chunkSize = 0;
    Std_ReturnType retVal = E_NOT_OK;
	uint32 Fls_len = 0;
    /*Get the MIN of two*/
    if (Fls_DrvObj.length < Fls_DrvObj.jobChunkSize)
    {
        chunkSize = Fls_DrvObj.length;
    }
    else
    {
        chunkSize = Fls_DrvObj.jobChunkSize;
    }

    SchM_Enter_Fls_FLS_EXCLUSIVE_AREA_0();

    switch(job) {
		case FLS_JOB_COMPARE:
            retVal = Fls_norCompare(chunkSize);
            break;
        case FLS_JOB_ERASE:
            retVal = Fls_norErase(chunkSize);
            break;
        case FLS_JOB_READ:
            retVal = Fls_norRead(chunkSize);
            break;
        case FLS_JOB_WRITE:
            retVal = Fls_norWrite(chunkSize);
            break;
		case FLS_JOB_BLANKCHECK:
            retVal = Fls_norBlankCheck(chunkSize);
            break;
        default:
            retVal = E_NOT_OK;
            break;
    }

    if (retVal == E_OK)
    {
        Fls_DrvObj.ramAddr = &Fls_DrvObj.ramAddr[chunkSize];
        if (job != FLS_JOB_ERASE)
        {
            Fls_DrvObj.flashAddr += chunkSize;
            /*Erase FlashAddr updated in Fls_norErase*/
        }
        Fls_DrvObj.length -= chunkSize;
        Fls_DrvObj.transferred += chunkSize;

        if( 0U == Fls_DrvObj.length )
        {
            Fls_DrvObj.jobResultType = MEMIF_JOB_OK;
            Fls_DrvObj.status = MEMIF_IDLE;
            Fls_DrvObj.jobType = FLS_JOB_NONE;
            Fls_DrvObj.transferred = Fls_len;
            if( Fls_DrvObj.Fls_JobEndNotification != NULL_PTR )
            {
                Fls_DrvObj.Fls_JobEndNotification();
            }
        }
    }
    else /*if retval == E_NOT_OK or E_COMPARE_MISMATCH*/
    {
        if ((E_BLANKCHECK_MISMATCH == retVal) || (E_COMPARE_MISMATCH == retVal))
        {
            Fls_DrvObj.status = MEMIF_IDLE;
            Fls_DrvObj.jobType = FLS_JOB_NONE;
            Fls_DrvObj.transferred = Fls_len;
            if (FLS_JOB_BLANKCHECK == job)
            {
				Det_ReportRuntimeError(FLS_MODULE_ID, FLS_INSTANCE_ID, FLS_SID_BLANK_CHECK, FLS_E_VERIFY_ERASE_FAILED);
            }
            else /*if (FLS_JOB_COMPARE == job)*/
            {
                Fls_DrvObj.jobResultType = MEMIF_BLOCK_INCONSISTENT;
				Det_ReportRuntimeError(FLS_MODULE_ID, FLS_INSTANCE_ID, FLS_SID_COMPARE, FLS_E_VERIFY_WRITE_FAILED);
            }
            if( Fls_DrvObj.Fls_JobErrorNotification != NULL_PTR )
            {
                Fls_DrvObj.Fls_JobErrorNotification();
            }
        }
        else /*if retVal == E_NOT_OK*/
        {
            /*Hardware/driver internal error occured*/
            ReportFlsError(job);
            if( Fls_DrvObj.Fls_JobErrorNotification != NULL_PTR )
            {
                   Fls_DrvObj.Fls_JobErrorNotification();
            }
        }
    }

    SchM_Exit_Fls_FLS_EXCLUSIVE_AREA_0();

    return;
}
/**
 *  \Function Name: Fls_VerifyData_priv
 *
 *  This function included in Fls_norCompare and verify data,if any mismatch 
 *  return FALSE  
 *
 */
static boolean Fls_VerifyData_priv(const uint8 *expData,
                const uint8 *rxData,
                uint32 length)
{
    uint32 idx = 0U;
    uint32 match = TRUE;
    boolean retVal = FALSE;
    uint8 *expData_local = (uint8 *)expData;
    uint8 *rxData_local = (uint8 *)rxData;

    for(idx = 0; ((idx < length) && (match != 0U)); idx++)
    {
        if(*expData_local != *rxData_local)
        {
            match = FALSE;
        }
        expData_local++;
        rxData_local++;
    }
    if(match == TRUE)
    {
        retVal = TRUE;
    }
    return retVal;
}

/**
 *  \Function Name: Fls_norCompare
 *
 *  This function Compares flash memory, if any mismatch return E_NOT_OK  
 *
 */
 
static Std_ReturnType Fls_norCompare(uint32 actualChunkSize)
{
    QSPI_Handle handle;
    uint32 addr             = Fls_DrvObj.flashAddr;
    uint32 len              = actualChunkSize;
    uint8 *readData_buf     = NULL;
    uint8 *expData_Buf      = Fls_DrvObj.ramAddr;
    Std_ReturnType retVal   = E_OK;

    handle = Fls_DrvObj.spiHandle;

    if ((handle != NULL_PTR) && (actualChunkSize > 0U))
    {
		QSPI_Transaction transaction;
		Fls_Qspi_TransactionInit(&transaction);
		transaction.addrOffset = addr;
		transaction.buf = (void *)readData_buf;
		transaction.count = len;
		retVal = Fls_Qspi_ReadMemMapMode(Fls_DrvObj.spiHandle, &transaction);
           if (E_OK == retVal)
           {
               if (Fls_VerifyData_priv(expData_Buf, (const uint8*)transaction.buf, len) == TRUE)
               {
                   retVal = E_OK;
               }
               else
               {
                   retVal = E_COMPARE_MISMATCH;
               }
           }
           else
           {
               retVal = E_NOT_OK;
           }
    }
    else
    {
        retVal = E_NOT_OK; /* Handle is NULL*/
    }
    return retVal;
}
/**
 *  \Function Name: Fls_norBlankCheck
 *
 *  Fls_norBlankCheck shall verify, whether a given memory area has been
 *  erased    
 *
 */
static Std_ReturnType Fls_norBlankCheck(uint32 actualChunkSize)
{
    QSPI_Handle handle;
    uint32 addr             = Fls_DrvObj.flashAddr;
    uint32 len              = actualChunkSize;
    uint8 *readData_buf     = NULL;
    Std_ReturnType retVal = E_OK;
    handle = Fls_DrvObj.spiHandle;

    if (handle != NULL_PTR)
    {
        /* Buffer containing the received data */
        uint8 expData_Buf[Fls_DrvObj.maxReadNormalMode];

        volatile uint32 idx;
        volatile uint8 *expData_ptr = expData_Buf;

        for(idx = 0; idx < len; idx++)
        {
            *expData_ptr = NOR_ERASED_DATA;
            expData_ptr++;
        }
        if(E_OK == retVal)
        {
			QSPI_Transaction transaction;
			Fls_Qspi_TransactionInit(&transaction);
			transaction.addrOffset = addr;
			transaction.buf = (void *)readData_buf;
			transaction.count = len;
			retVal = Fls_Qspi_ReadMemMapMode(Fls_DrvObj.spiHandle, &transaction);
            if (E_OK == retVal)
            {
                if (Fls_VerifyData_priv(expData_Buf, (const uint8*)transaction.buf, len) == TRUE)
                {
                    retVal = E_OK;
                }
                else
                {
                    retVal = E_BLANKCHECK_MISMATCH;
                }
            }
            else
            {
                retVal = E_NOT_OK;
            }
        }
    }
    else
    {
        retVal = E_NOT_OK; /*Handle is NULL*/
    }
    return retVal;
}
/**
 *  \Function Name: Fls_norRead
 *
 *   This function read flash memory    
 *
 */
static Std_ReturnType Fls_norRead(uint32 actualChunkSize)
{
    Std_ReturnType retVal = E_OK;
	uint32 offset = Fls_DrvObj.flashAddr;
	uint8 *buf = Fls_DrvObj.ramAddr;
	uint32 sectorSize;
	uint32 sectorPageSize;
	uint32 numberOfSectors;
	uint32 block;
	
	sectorSize = Fls_DrvObj.sectorList[0].sectorSize;
	sectorPageSize = Fls_DrvObj.sectorList[0].sectorPageSize;
	numberOfSectors = Fls_DrvObj.sectorList[0].numberOfSectors;
	block = sectorSize/sectorPageSize;
	
    /* Validate address input */
    if (( offset + actualChunkSize) > (numberOfSectors*block*sectorPageSize))
    {
        retVal = E_NOT_OK;
    }
    if (actualChunkSize > 0U)
    {
        QSPI_Transaction transaction;

        Fls_Qspi_TransactionInit(&transaction);
        transaction.addrOffset = offset;
        transaction.buf = (void *)buf;
        transaction.count = actualChunkSize;
        retVal = Fls_Qspi_ReadMemMapMode(Fls_DrvObj.spiHandle, &transaction);
    }
	else
	{
		retVal = E_NOT_OK;
	}
    return retVal;
}
/**
 *  \Function Name: Fls_norWrite
 *
 *   This function Write to flash   
 *
 */
static Std_ReturnType Fls_norWrite(uint32 actualChunkSize)
{
    Std_ReturnType retVal = E_OK;
    uint32 offset = Fls_DrvObj.flashAddr;
	uint8 *buf = Fls_DrvObj.ramAddr;
	uint32 sectorSize;
	uint32 sectorPageSize;
	uint32 numberOfSectors;
	uint32 block;
	uint32 page = 0;
	
	sectorSize = Fls_DrvObj.sectorList[0].sectorSize;
	sectorPageSize = Fls_DrvObj.sectorList[0].sectorPageSize;
	numberOfSectors = Fls_DrvObj.sectorList[0].numberOfSectors;
	block = sectorSize/sectorPageSize;
	
    /* Validate address input */
    if ((( offset + actualChunkSize) > (numberOfSectors*block*sectorPageSize)) || 
						((uint32)(offset % FLASH_PAGE_SIZE) > page))
    {
        retVal = E_NOT_OK;
    }
    if(actualChunkSize > 0U)
    {
        uint32 pageSize, chunkLen, actual;
        uint8 cmdWren = NOR_CMD_WREN;
        QSPI_Transaction transaction;

        pageSize = NOR_PAGE_SIZE;
        chunkLen = pageSize;

        for (actual = 0; actual < actualChunkSize; actual += chunkLen)
        {
            retVal = Nor_QspiCmdWrite(Fls_DrvObj.spiHandle, cmdWren, QSPI_CMD_INVALID_ADDR, NULL, 0);

            if(retVal == E_OK)
            {
                retVal = Nor_QspiWriteEnableLatched(Fls_DrvObj.spiHandle,NOR_WRR_WRITE_TIMEOUT);
            }

            if(retVal == E_OK)
            {
                /* Send Page Program command */
                if((actualChunkSize - actual) < (pageSize))
                {
                    chunkLen = (actualChunkSize - actual);
                }
                else
                {
                    chunkLen = pageSize;
                }

                Fls_Qspi_TransactionInit(&transaction);
                transaction.addrOffset = offset;
                transaction.buf = (void *)(buf + actual);
                transaction.count = chunkLen;
                retVal = Fls_Qspi_WriteConfigMode(Fls_DrvObj.spiHandle, &transaction);
            }

            if(retVal == E_OK)
            {
                retVal = Nor_QspiWaitReady(Fls_DrvObj.spiHandle,NOR_PAGE_PROG_TIMEOUT);
            }

            if(retVal == E_OK)
            {
                offset += chunkLen;
            }
            else
            {
                break;
            }
        }
    }
	else
	{
		retVal = E_NOT_OK;
	}	
    return retVal;
}
/**
 *  \Function Name: Fls_norErase
 *
 *   This function Erase a block from flash 
 *
 */
static Std_ReturnType Fls_norErase(uint32 actualChunkSize)
{
    Std_ReturnType retVal = E_OK;

    uint8  cmd = NOR_CMD_BLOCK_ERASE;
    uint32 cmdAddr = Fls_DrvObj.flashAddr;
    uint8  cmdWren = NOR_CMD_WREN;
	if(actualChunkSize == 0U)
	{
		retVal = E_NOT_OK;
	}
	else
	{
	if(Nor_QspiCmdWrite(Fls_DrvObj.spiHandle, cmdWren, QSPI_CMD_INVALID_ADDR, NULL, 0) == E_OK)
	{
		if(Nor_QspiWaitReady(Fls_DrvObj.spiHandle,NOR_WRR_WRITE_TIMEOUT) == E_OK)
		{
			if(Nor_QspiCmdWrite(Fls_DrvObj.spiHandle, cmd, cmdAddr, NULL, 0) == E_OK)
			{
				if(Nor_QspiWaitReady(Fls_DrvObj.spiHandle,NOR_BULK_ERASE_TIMEOUT) == E_OK)
				{
					retVal = E_OK;
				}
				else
                {
                    retVal = E_NOT_OK;
                }
			}
			else
            {
                retVal = E_NOT_OK;
            }
		}
		else
        {
            retVal = E_NOT_OK;
        }
	}
	else
    {
        retVal = E_NOT_OK;
    }
	}
    return retVal;
}

/**
 *  \Function Name: Fls_copyConfig
 *
 *   Configuration parameters are copying to drvObj, 
 *   this function included with Fls_init
 *
 */
void Fls_copyConfig(Fls_DriverObjType *drvObj,
    const Fls_ConfigType *cfgPtr)
{
	if((drvObj != NULL_PTR) && (cfgPtr != NULL_PTR))
	{
		drvObj->Fls_JobEndNotification = cfgPtr->Fls_JobEndNotification;
		drvObj->Fls_JobErrorNotification = cfgPtr->Fls_JobErrorNotification;
		drvObj->maxReadNormalMode = cfgPtr->maxReadNormalMode;
		drvObj->maxWriteNormalMode = cfgPtr->maxWriteNormalMode;
		drvObj->sectorList[0] = cfgPtr->sectorList[0];
		drvObj->flsBaudRateDiv = cfgPtr->flsBaudRateDiv;
	}
    return;
}
/**
 *  \Function Name: Fls_resetDrvObj
 *
 *   All Driver parameter's reseting during initialize time. 
 *
 */
void Fls_resetDrvObj(Fls_DriverObjType *drvObj)
{
	if(drvObj != NULL_PTR)
	{
		drvObj->Fls_JobEndNotification = NULL;
		drvObj->Fls_JobErrorNotification = NULL;
		drvObj->maxReadNormalMode = NULL;
		drvObj->maxWriteNormalMode = NULL;
		drvObj->status = MEMIF_UNINIT;
		drvObj->jobResultType = MEMIF_JOB_OK;
		drvObj->jobType = FLS_JOB_NONE;
		drvObj->flashAddr = NULL;
		drvObj->ramAddr = NULL;
		drvObj->length = NULL;
		drvObj->mode = MEMIF_MODE_SLOW;
		drvObj->jobChunkSize = NULL;
		drvObj->spiHandle = NULL;
		drvObj->transferred = NULL;
		drvObj->flsBaudRateDiv=NULL;
	}
    return;
}


#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"
