/*! \file    
**********************************************************************************
* Title:                            Discretix SST API Source file
*
* Filename:                         nvs_host.c
*
* Project, Target, subsystem:       NVS Host IF
* 
* Created:                          01.07.2007
*
* Modified:
*
* \Author                           Ira Boguslavsky
*
* \Remarks
*           Copyright (C) 2006 by Discretix Technologies Ltd. All Rights reserved.
**********************************************************************************/

/************* Include Files ****************/
#include "DX_VOS_Sem.h"
#include "nvs_host.h"
#ifdef DX_SEP_SIMULATION
    #include "nvs_host_duplicate_wrapper.h"
#endif
#include "NVS.h"
#include "SEPDriver.h"
#include "error.h"
#include "nvs_host_op_code.h"

#ifndef DX_NO_TLK_SCLK_SUPPORT
#include "DX_VOS_File.h"
	#define NVS_TLK_SCLK_MEMORY_ID                        (0xFFFFFFFF)
	extern DxVosFile       g_TLK_SCLK_NVSMemoryId;
#endif

/************************ Defines ******************************/
/************************ Enums ******************************/
/************************ Typedefs ******************************/
/************************ Global Data ******************************/
DxVosSem g_nvsSemaphore;
/************* Private function prototype ****************/
#ifndef SST_SEP_SIMULATOR_ENV
	DxError_t NVSThread_ProtocolFunction     (void *pData);
#endif
static void      NVSThread_SendResponse         (DxUint32_t *aInputBufferParam_ptr,
                                                 DxUint32_t  aInputBufferParamLengthInBytes,
                                                 DxUint32_t  aInputBufferMaxLengthInBytes);
static DxError_t NVSHost_InternalMemRead		(void);
static DxError_t NVSHost_InternalMemWrite		(void);
static DxError_t NVSHost_ExternalMemRead		(void);
static DxError_t NVSHost_ExternalMemWrite		(void);

/************************ Public Functions ******************************/

/************************************************************************/
/*             NVSHost_Parser                                           */
/************************************************************************/
DxError_t NVSHost_Parser(void)
{
	DxError_t errorRC;
	DxUint32_t opCode = *((DxUint32_t*)(DX_PROTOCOL_SHARED_MEMORY_OP_CODE_ADDRESS));
	
	/* Read parameters from shared memory and perform READ or WRITE request */
	switch (opCode)    
	{
	case NVS_SEP_OP_CODE_EXTERNAL_MEM_READ:           
		errorRC = NVSHost_ExternalMemRead();
		break;

	case NVS_SEP_OP_CODE_EXTERNAL_MEM_WRITE:           
		errorRC = NVSHost_ExternalMemWrite();
		break;

	case NVS_SEP_OP_CODE_INTERNAL_MEM_READ:            
		errorRC = NVSHost_InternalMemRead();
		break;

	case NVS_SEP_OP_CODE_INTERNAL_MEM_WRITE:           
		errorRC = NVSHost_InternalMemWrite();
		break;

	default:
		return NVS_INVALID_PARAM;
	}

	return errorRC;
}
/************************ Internal Functions ******************************/
/************************************************************************/
/*                        NVSHost_InternalMemRead                     */
/************************************************************************/
static DxError_t NVSHost_InternalMemRead ( void )
{
    DxError_t               errorRC;
    DxNvsMemoryId_t         memoryId;
    DxUint32_t              offset;
    DxUint32_t             *paramOutBuffer_ptr = (DxUint32_t*)DX_PROTOCOL_SHARED_MEMORY_OP_CODE_ADDRESS;
    DxUint32_t              buffLenInBytes;
    DxUint32_t              bytesReadInBytes;
    DxUint32_t             *sharedMemory_ptr = (DxUint32_t*)DX_PROTOCOL_SHARED_MEMORY_OP_CODE_ADDRESS;

    /* Get next word in shared memory. The first word is Operation code */
    sharedMemory_ptr++;

   /************************************************************************/
    /* Fill input parameters for NVS_Read function and perform request      */
    /************************************************************************/
    memoryId         = (DxNvsMemoryId_t)(*sharedMemory_ptr++);
    offset           = (DxUint32_t)   (*sharedMemory_ptr++);
    buffLenInBytes   = (DxUint32_t)   (*sharedMemory_ptr);

   /************************************************************************/
    /* Support the special memory ID for secured clock       			   */
    /**********************************************************************/
#if 0 
	/*The memory ID is the correct pointer in teh files table of the nvs*/
	if (NVS_TLK_SCLK_MEMORY_ID == memoryId)
	{
		memoryId = (DxNvsMemoryId_t)g_TLK_SCLK_NVSMemoryId;
	}
#endif
	errorRC =   NVS_Read (memoryId,
	                      offset,
	                      /* First 3 bytes are used for opcode, RC and len TEMP TEMP */
	                      (char*)(paramOutBuffer_ptr + DX_3_WORDS_PARAMS), 
	                      buffLenInBytes,
	                      &bytesReadInBytes);

	if (errorRC != DX_SUCCESS) 
	    goto exit_thread_read;
    
    /************************************************************************/
    /* Prepare output buffer for response to SeP                            */
    /************************************************************************/
    paramOutBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_INTERNAL_MEM_READ;
    paramOutBuffer_ptr[1] = errorRC;
    paramOutBuffer_ptr[2] = (DxUint32_t)bytesReadInBytes;

    /************************************************************************/
    /* Send Response to SeP                                                 */
    /************************************************************************/
    NVSThread_SendResponse (paramOutBuffer_ptr,
                            buffLenInBytes + DX_3_WORDS_PARAMS * sizeof(DxUint32_t), 
                            NVS_THREAD_WORD_ROUND_UP(buffLenInBytes) + DX_3_WORDS_PARAMS * sizeof(DxUint32_t));

	return DX_SUCCESS;
    /************************************************************************/
    /* Send Error Response to SeP                                           */
    /************************************************************************/
exit_thread_read:
    paramOutBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_INTERNAL_MEM_READ;
    paramOutBuffer_ptr[1] = errorRC;
    NVSThread_SendResponse (paramOutBuffer_ptr,
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t), 
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t));
    return errorRC;
}

/************************************************************************/
/*                      NVSHost_ExternalMemRead                         */
/************************************************************************/
static DxError_t NVSHost_ExternalMemRead ( void )
{
    DxError_t               errorRC;
    DxNvsMemoryId_t         memoryId;
    DxUint32_t              offset;
    DxUint32_t              bufferVirtAddr;
    DxChar_t               *buffer_ptr; 
    DxUint32_t              buffLenInBytes;
    DxUint32_t              bytesReadInBytes;
    DxUint32_t             *sharedMemory_ptr = (DxUint32_t*)DX_PROTOCOL_SHARED_MEMORY_OP_CODE_ADDRESS;
    DxUint32_t              paramInBuffer_ptr[DX_3_WORDS_PARAMS];

    /* Get next word in shared memory. The first word is Operation code */
    sharedMemory_ptr++;

    /************************************************************************/
    /* Fill input parameters for NVS_Read function and perform request      */
    /************************************************************************/
    memoryId         = (DxNvsMemoryId_t)(*sharedMemory_ptr++);
    offset           = (DxUint32_t)(*sharedMemory_ptr++);
    buffLenInBytes   = (DxUint32_t)(*sharedMemory_ptr++);
    buffer_ptr       = (DxChar_t*)(*sharedMemory_ptr);
	  
    SEPDriver_StaticPhysAddrToVirt((DxUint32_t)buffer_ptr , &bufferVirtAddr); 

    errorRC =   NVS_Read (memoryId,
                          offset,
                          (DxUint8_t*)bufferVirtAddr,
                          buffLenInBytes,
                         &bytesReadInBytes);

    if (errorRC != DX_SUCCESS) 
        goto exit_thread_read;

    /************************************************************************/
    /* Prepare input buffer for response to SeP                             */
    /************************************************************************/
    paramInBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_EXTERNAL_MEM_READ;
    paramInBuffer_ptr[1] = errorRC;
    paramInBuffer_ptr[2] = (DxUint32_t)bytesReadInBytes;

    /************************************************************************/
    /* Send Response to SeP                                                 */
    /************************************************************************/
    NVSThread_SendResponse (paramInBuffer_ptr,
                            DX_3_WORDS_PARAMS * sizeof(DxUint32_t), 
                            DX_3_WORDS_PARAMS * sizeof(DxUint32_t));

	return DX_SUCCESS;
    /************************************************************************/
    /* Send Error Response to SeP                                           */
    /************************************************************************/
exit_thread_read:
    paramInBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_EXTERNAL_MEM_READ;
    paramInBuffer_ptr[1] = errorRC;
    NVSThread_SendResponse (paramInBuffer_ptr,
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t), 
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t));
    return errorRC;

}

/************************************************************************/
/*                 NVSHost_InternalMemWrite                            */
/************************************************************************/
static DxError_t NVSHost_InternalMemWrite ( void )
{
    DxError_t               errorRC;
    DxNvsMemoryId_t           memoryId;
    DxUint32_t              offset;
    DxUint32_t              buffLenInBytes;
    DxUint32_t              bytesWrittenInBytes;
    DxUint32_t             *sharedMemory_ptr = (DxUint32_t*)DX_PROTOCOL_SHARED_MEMORY_OP_CODE_ADDRESS;

    DxUint32_t              paramInBuffer_ptr         [DX_3_WORDS_PARAMS];

    /* Get next word in shared memory. The first word is Operation code */
    sharedMemory_ptr++;

    /************************************************************************/
    /* Fill input parameters for NVS_Read function and perform request      */
    /************************************************************************/
    memoryId         = (DxNvsMemoryId_t)(*sharedMemory_ptr++);
    offset           = (DxUint32_t)(*sharedMemory_ptr++);
    buffLenInBytes   = (DxUint32_t)*sharedMemory_ptr++;

#if 0//ndef DX_NO_TLK_SCLK_SUPPORT
	if (NVS_TLK_SCLK_MEMORY_ID == memoryId)
	{
		memoryId = (DxNvsMemoryId_t)g_TLK_SCLK_NVSMemoryId;
	}
#endif

    errorRC =   NVS_Write ( memoryId,
                            offset,
                            (char*)sharedMemory_ptr,
                            buffLenInBytes,
                            &bytesWrittenInBytes);
    if (errorRC != DX_SUCCESS) 
        goto exit_thread_write;

    /************************************************************************/
    /* Prepare input buffer for response to SeP                             */
    /************************************************************************/
    paramInBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_INTERNAL_MEM_WRITE;
    paramInBuffer_ptr[1] = errorRC;
    paramInBuffer_ptr[2] = (DxUint32_t)bytesWrittenInBytes;

    /************************************************************************/
    /* Send Response to SeP                                                 */
    /************************************************************************/
    NVSThread_SendResponse (paramInBuffer_ptr,
                            DX_3_WORDS_PARAMS * sizeof(DxUint32_t), 
                            DX_3_WORDS_PARAMS * sizeof(DxUint32_t));

	return DX_SUCCESS;
    /************************************************************************/
    /* Send Error Response to SeP                                           */
    /************************************************************************/
exit_thread_write:
    paramInBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_INTERNAL_MEM_WRITE;
    paramInBuffer_ptr[1] = errorRC;
    NVSThread_SendResponse (paramInBuffer_ptr,
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t), 
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t));
    return errorRC;
}/* END OF NVS_Write */

/************************************************************************/
/*              NVSHost_ExternalMemWrite                              */
/************************************************************************/
static DxError_t NVSHost_ExternalMemWrite ( void )
{
    DxError_t               errorRC;
    DxNvsMemoryId_t         memoryId;
    DxUint32_t              offset;
    DxChar_t*               buffer_ptr;
    DxUint32_t              bufferVirtAddr;
    DxUint32_t              buffLenInBytes;
    DxUint32_t              bytesWrittenInBytes;
    DxUint32_t*             sharedMemory_ptr = (DxUint32_t*)DX_PROTOCOL_SHARED_MEMORY_OP_CODE_ADDRESS;

    DxUint32_t              paramInBuffer_ptr         [DX_3_WORDS_PARAMS];

    /* Get next word in shared memory. The first word is Operation code */
    sharedMemory_ptr++;

    /************************************************************************/
    /* Fill input parameters for NVS_Read function and perform request      */
    /************************************************************************/
    memoryId         = (DxNvsMemoryId_t)(*sharedMemory_ptr++);
    offset           = (DxUint32_t)(*sharedMemory_ptr++);
    buffLenInBytes   = (DxUint32_t)*sharedMemory_ptr++;
	  buffer_ptr       = (DxChar_t*)*sharedMemory_ptr;
	
	  SEPDriver_StaticPhysAddrToVirt((DxUint32_t)buffer_ptr , &bufferVirtAddr); 
	
    errorRC =   NVS_Write ( memoryId,
                            offset,
                            (DxUint8_t*)bufferVirtAddr,
                            buffLenInBytes,
                            &bytesWrittenInBytes);
    if (errorRC != DX_SUCCESS) 
        goto exit_thread_write;

    /************************************************************************/
    /* Prepare input buffer for response to SeP                             */
    /************************************************************************/
    paramInBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_EXTERNAL_MEM_WRITE;
    paramInBuffer_ptr[1] = errorRC;
    paramInBuffer_ptr[2] = (DxUint32_t)bytesWrittenInBytes;

    /************************************************************************/
    /* Send Response to SeP                                                 */
    /************************************************************************/
    NVSThread_SendResponse (paramInBuffer_ptr,
        DX_3_WORDS_PARAMS * sizeof(DxUint32_t), 
        DX_3_WORDS_PARAMS * sizeof(DxUint32_t));

	return DX_SUCCESS;
    /************************************************************************/
    /* Send Error Response to SeP                                           */
    /************************************************************************/
exit_thread_write:
    paramInBuffer_ptr[0] = (DxUint32_t)NVS_SEP_OP_CODE_EXTERNAL_MEM_WRITE;
    paramInBuffer_ptr[1] = errorRC;
    NVSThread_SendResponse (paramInBuffer_ptr,
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t), 
                            DX_2_WORDS_PARAMS * sizeof(DxUint32_t));
    return errorRC;
}/* END OF NVS_Write */



/************************************************************************/
/*                NVSThread_ProtocolFunction                           */
/************************************************************************/

/*TODO remove this function, only used by the SST SEP simulator*/
DxError_t NVSThread_ProtocolFunction(void *pData)
{
    DxError_t   errorRC;

    while (DX_TRUE)
    {
        /************************************************************************/
        /* Wait for event from SeP                                              */
        /************************************************************************/
        errorRC = SEPDriver_WaitForResponse(SEP_DRIVER_POLLING_WITH_CALLBACK,
                                            SEP_DRIVER_NVS_EVENT,
                                            NVSHost_Parser,
                                            SEP_DRIVER_TIMEOUT_5_SECONDS);

        if (errorRC != DX_SUCCESS) 
            goto exit_thread_protocol_func;
    }
    
exit_thread_protocol_func:
    return errorRC;
}

/************************************************************************/
/*                      NVSThread_SendResponse                          */
/************************************************************************/
static void NVSThread_SendResponse( DxUint32_t *aInputBufferParam_ptr,
                                    DxUint32_t  aInputBufferParamLengthInBytes,
                                    DxUint32_t  aInputBufferMaxLengthInBytes)
{
    DxUint32_t          sramOffset = 0;

    /************************************************************************/
    /*  Start message                                                       */
    /************************************************************************/
    SEPDriver_StartMessage(&sramOffset);
    
    /************************************************************************/
    /*  Send message                                                        */
    /************************************************************************/
    SEPDriver_WriteParamater((DxUint32_t)aInputBufferParam_ptr,
                                         aInputBufferParamLengthInBytes,
                                         aInputBufferMaxLengthInBytes,
                                        &sramOffset, 
                                         DX_ENDIANESS_FLAG);
    

    /************************************************************************/
    /* End message (signal the SEP)                                         */
    /************************************************************************/
    SEPDriver_EndReplyMessage(sramOffset);
}



