/**
 * @file
 *
 * S3 save/restore script
 *
 *
 *
 * @xrefitem bom "File Content Label" "Release Content"
 * @e project:     AGESA
 * @e sub-project: GNB
 * @e \$Revision: 20539 $   @e \$Date: 2009-10-14 10:48:54 -0700 (Wed, 14 Oct 2009) $
 *
 */
/*
*****************************************************************************
*
* Copyright (c) 2011, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Advanced Micro Devices, Inc. nor the names of
*       its contributors may be used to endorse or promote products derived
*       from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 ADVANCED MICRO DEVICES, INC. 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.
*
* ***************************************************************************
*
*/

/*----------------------------------------------------------------------------------------
 *                             M O D U L E S    U S E D
 *----------------------------------------------------------------------------------------
 */
#include "Porting.h"
#include "AMD.h"
#include "amdlib.h"
#include "heapManager.h"
#include "S3SaveState.h"
#include "Filecode.h"
#define FILECODE PROC_COMMON_S3SAVESTATE_FILECODE
/*----------------------------------------------------------------------------------------
 *                   D E F I N I T I O N S    A N D    M A C R O S
 *----------------------------------------------------------------------------------------
 */


/*----------------------------------------------------------------------------------------
 *                  T Y P E D E F S     A N D     S T R U C T U  R E S
 *----------------------------------------------------------------------------------------
 */
extern S3_SCRIPT_CONFIGURATION OptionS3ScriptConfiguration;

/*----------------------------------------------------------------------------------------
 *           P R O T O T Y P E S     O F     L O C A L     F U  N C T I O N S
 *----------------------------------------------------------------------------------------
 */

/*----------------------------------------------------------------------------------------*/
/**
 * Initialize S3 Script framework
 *
 *
 *
 * @param[in] StdHeader          Pointer to standard header
 */
AGESA_STATUS
S3ScriptInit (
  IN      AMD_CONFIG_PARAMS   *StdHeader
  )
{
  return OptionS3ScriptConfiguration.Init (StdHeader);
}

/*----------------------------------------------------------------------------------------*/
/**
 * Initialize S3 Script framework
 *
 *
 *
 * @param[in] StdHeader          Pointer to standard header
 */
AGESA_STATUS
S3ScriptInitStateStub (
  IN      AMD_CONFIG_PARAMS   *StdHeader
  )
{
  return AGESA_SUCCESS;
}

/*----------------------------------------------------------------------------------------*/
/**
 * Initialize S3 Script framework
 *
 *
 *
 * @param[in] StdHeader          Pointer to standard header
 */
AGESA_STATUS
S3ScriptInitState (
  IN      AMD_CONFIG_PARAMS   *StdHeader
  )
{
  AGESA_STATUS          Status;
  ALLOCATE_HEAP_PARAMS  AllocHeapParams;

  AllocHeapParams.RequestedBufferSize = S3_TABLE_LENGTH;
  AllocHeapParams.BufferHandle = AMD_S3_SCRIPT_SAVE_TABLE_HANDLE;
  AllocHeapParams.Persist = StdHeader->HeapStatus;
  Status = HeapAllocateBuffer (&AllocHeapParams, StdHeader);
  if (Status == AGESA_SUCCESS) {
    ((S3_SAVE_TABLE_HEADER *) AllocHeapParams.BufferPtr)->TableLength = S3_TABLE_LENGTH;
    ((S3_SAVE_TABLE_HEADER *) AllocHeapParams.BufferPtr)->SaveOffset = sizeof (S3_SAVE_TABLE_HEADER);
  }
  return Status;
}

/*----------------------------------------------------------------------------------------*/
/**
 * Initialize S3 Script framework
 *
 *
 *
 * @param[in]     StdHeader          Pointer to standard header
 * @param[in,out] S3SaveTable        S3 save table header
 */
STATIC AGESA_STATUS
S3SaveStateExtendTableLenth (
  IN       AMD_CONFIG_PARAMS     *StdHeader,
  IN OUT   S3_SAVE_TABLE_HEADER  **S3SaveTable
  )
{
  AGESA_STATUS          Status;
  ALLOCATE_HEAP_PARAMS  AllocHeapParams;
  VOID                  *TempBuffer;
  UINT16                NewTableLength;
  UINT16                CurrentTableLength;
  //Allocate temporary buffer
  NewTableLength = (*S3SaveTable)->TableLength + S3_TABLE_LENGTH_INCREMENT;
  AllocHeapParams.RequestedBufferSize = NewTableLength;
  AllocHeapParams.BufferHandle = AMD_S3_SCRIPT_TEMP_BUFFER_HANDLE;
  AllocHeapParams.Persist = StdHeader->HeapStatus;
  Status = HeapAllocateBuffer (&AllocHeapParams, StdHeader);
  if (Status != AGESA_SUCCESS) {
    return Status;
  }
  //Save current table length
  CurrentTableLength = (*S3SaveTable)->TableLength;
  //Update table length
  (*S3SaveTable)->TableLength = NewTableLength;
  //Copy S3 save toable to temporary location
  LibAmdMemCopy (AllocHeapParams.BufferPtr, *S3SaveTable, CurrentTableLength, StdHeader);
  //Save pointer to temp buffer
  TempBuffer = AllocHeapParams.BufferPtr;
  // Free original S3 save buffer
  HeapDeallocateBuffer (AMD_S3_SCRIPT_SAVE_TABLE_HANDLE, StdHeader);

  AllocHeapParams.RequestedBufferSize = NewTableLength;
  AllocHeapParams.BufferHandle = AMD_S3_SCRIPT_SAVE_TABLE_HANDLE;
  AllocHeapParams.Persist = StdHeader->HeapStatus;
  Status = HeapAllocateBuffer (&AllocHeapParams, StdHeader);
  if (Status != AGESA_SUCCESS) {
    return Status;
  }
  LibAmdMemCopy (AllocHeapParams.BufferPtr, TempBuffer, AllocHeapParams.RequestedBufferSize, StdHeader);
  *S3SaveTable = (S3_SAVE_TABLE_HEADER*) AllocHeapParams.BufferPtr;
  HeapDeallocateBuffer (AMD_S3_SCRIPT_TEMP_BUFFER_HANDLE, StdHeader);
  return Status;
}


/*----------------------------------------------------------------------------------------*/
/**
 * Initialize S3 Script framework
 *
 *
 *
 * @param[in]  StdHeader          Pointer to standard header
 * @param[out] S3SaveTable        S3 save table header
 */
AGESA_STATUS
S3ScriptGetS3SaveTable (
  IN       AMD_CONFIG_PARAMS     *StdHeader,
     OUT   S3_SAVE_TABLE_HEADER  **S3SaveTable
  )
{
  AGESA_STATUS          Status;
  LOCATE_HEAP_PTR       LocHeapParams;
  LocHeapParams.BufferHandle = AMD_S3_SCRIPT_SAVE_TABLE_HANDLE;
  Status = HeapLocateBuffer (&LocHeapParams, StdHeader);
  if (Status != AGESA_SUCCESS) {
    *S3SaveTable = NULL;
    return Status;
  }
  *S3SaveTable = (S3_SAVE_TABLE_HEADER *) LocHeapParams.BufferPtr;
  return AGESA_SUCCESS;
}


/*----------------------------------------------------------------------------------------*/
/**
 * Save S3 write opcode
 *
 *
 *
 * @param[in] StdHeader          Pointer to standard header
 * @param[in] OpCode             Operation opcode
 * @param[in] Width              Width
 * @param[in] Address            Register address
 * @param[in] Count              Number of register writes
 * @param[in] Buffer             Pointer to write buffer
 */
AGESA_STATUS
S3SaveStateSaveWriteOp (
  IN      AMD_CONFIG_PARAMS   *StdHeader,
  IN      UINT16              OpCode,
  IN      ACCESS_WIDTH        Width,
  IN      UINT64              Address,
  IN      UINT32              Count,
  IN      VOID                *Buffer
  )
{
  S3_SAVE_TABLE_HEADER    *S3SaveTablePtr;
  S3_WRITE_OP_HEADER      *SaveOffsetPtr;
  UINT32                  OpCodeLength;
  UINT32                  WidthLength;
  AGESA_STATUS            Status;

  Status = S3ScriptGetS3SaveTable (StdHeader, &S3SaveTablePtr);
  if (Status != AGESA_SUCCESS) {
    return Status;
  }
  WidthLength = LibAmdAccessWidth (Width);
  OpCodeLength = sizeof (S3_WRITE_OP_HEADER) + WidthLength * Count;
  if ((S3SaveTablePtr->SaveOffset + OpCodeLength) > S3SaveTablePtr->TableLength) {
    Status = S3SaveStateExtendTableLenth (StdHeader, &S3SaveTablePtr);
    if (Status != AGESA_SUCCESS) {
      return Status;
    }
  }
  SaveOffsetPtr = (S3_WRITE_OP_HEADER *) ((UINT8 *) S3SaveTablePtr + S3SaveTablePtr->SaveOffset);
  SaveOffsetPtr->OpCode = OpCode;
  SaveOffsetPtr->Width = Width;
  SaveOffsetPtr->Count = Count;
  SaveOffsetPtr->Address = Address;
  LibAmdMemCopy (
    (UINT8 *) SaveOffsetPtr + sizeof (S3_WRITE_OP_HEADER),
    Buffer,
    WidthLength * Count,
    StdHeader
    );
  S3SaveTablePtr->SaveOffset += OpCodeLength;
  return AGESA_SUCCESS;
}

/*----------------------------------------------------------------------------------------*/
/**
 * Save S3 write opcode
 *
 *
 *
 * @param[in] StdHeader          Pointer to standard header
 * @param[in] OpCode             Operation opcode
 * @param[in] Width              Width
 * @param[in] Address            Register address
 * @param[in] Data               Pointer to data
 * @param[in] DataMask           Pointer data mask
 */
AGESA_STATUS
S3SaveStateSaveReadWriteOp (
  IN      AMD_CONFIG_PARAMS   *StdHeader,
  IN      UINT16              OpCode,
  IN      ACCESS_WIDTH        Width,
  IN      UINT64              Address,
  IN      VOID                *Data,
  IN      VOID                *DataMask
  )
{

  S3_SAVE_TABLE_HEADER    *S3SaveTablePtr;
  S3_READ_WRITE_OP_HEADER *SaveOffsetPtr;
  UINT32                  OpCodeLength;
  UINT32                  WidthLength;
  AGESA_STATUS            Status;

  Status = S3ScriptGetS3SaveTable (StdHeader, &S3SaveTablePtr);
  if (Status != AGESA_SUCCESS) {
    return Status;
  }
  WidthLength = LibAmdAccessWidth (Width);
  OpCodeLength = sizeof (S3_READ_WRITE_OP_HEADER) + WidthLength * 2;
  if ((S3SaveTablePtr->SaveOffset + OpCodeLength) > S3SaveTablePtr->TableLength) {
    Status = S3SaveStateExtendTableLenth (StdHeader, &S3SaveTablePtr);
    if (Status != AGESA_SUCCESS) {
      return Status;
    }
  }

  SaveOffsetPtr = (S3_READ_WRITE_OP_HEADER *) ((UINT8 *) S3SaveTablePtr + S3SaveTablePtr->SaveOffset);
  SaveOffsetPtr->OpCode = OpCode;
  SaveOffsetPtr->Width = Width;
  SaveOffsetPtr->Address = Address;

  LibAmdMemCopy (
    (UINT8 *) SaveOffsetPtr + sizeof (S3_READ_WRITE_OP_HEADER),
    Data,
    WidthLength,
    StdHeader
    );
  LibAmdMemCopy (
    (UINT8 *) SaveOffsetPtr + sizeof (S3_READ_WRITE_OP_HEADER) + WidthLength,
    DataMask,
    WidthLength,
    StdHeader
    );
  S3SaveTablePtr->SaveOffset += OpCodeLength;
  return AGESA_SUCCESS;
}


/*----------------------------------------------------------------------------------------*/
/**
 * Save S3 poll opcode
 *
 *
 *
 * @param[in] StdHeader          Pointer to standard header
 * @param[in] OpCode             Operation opcode
 * @param[in] Width              Width
 * @param[in] Address            Register address
 * @param[in] Data               Pointer to data
 * @param[in] DataMask           Pointer data mask
 * @param[in] Delay              Time delay for poll
 */
AGESA_STATUS
S3SaveStateSavePollOp (
  IN      AMD_CONFIG_PARAMS   *StdHeader,
  IN      UINT16              OpCode,
  IN      ACCESS_WIDTH        Width,
  IN      UINT64              Address,
  IN      VOID                *Data,
  IN      VOID                *DataMask,
  IN      UINT64              Delay
  )
{

  S3_SAVE_TABLE_HEADER    *S3SaveTablePtr;
  S3_POLL_OP_HEADER       *SaveOffsetPtr;
  UINT32                  OpCodeLength;
  UINT32                  WidthLength;
  AGESA_STATUS            Status;

  Status = S3ScriptGetS3SaveTable (StdHeader, &S3SaveTablePtr);
  if (Status != AGESA_SUCCESS) {
    return Status;
  }
  WidthLength = LibAmdAccessWidth (Width);
  OpCodeLength = sizeof (S3_POLL_OP_HEADER) + WidthLength * 2;
  if ((S3SaveTablePtr->SaveOffset + OpCodeLength) > S3SaveTablePtr->TableLength) {
    Status = S3SaveStateExtendTableLenth (StdHeader, &S3SaveTablePtr);
    if (Status != AGESA_SUCCESS) {
      return Status;
    }
  }

  SaveOffsetPtr = (S3_POLL_OP_HEADER *) ((UINT8 *) S3SaveTablePtr + S3SaveTablePtr->SaveOffset);
  SaveOffsetPtr->OpCode = OpCode;
  SaveOffsetPtr->Width = Width;
  SaveOffsetPtr->Delay = Delay;
  SaveOffsetPtr->Address = Address;

  LibAmdMemCopy (
    (UINT8 *) SaveOffsetPtr + sizeof (S3_POLL_OP_HEADER),
    Data,
    WidthLength,
    StdHeader
    );
  LibAmdMemCopy (
    (UINT8 *) SaveOffsetPtr + sizeof (S3_POLL_OP_HEADER) + WidthLength,
    DataMask,
    WidthLength,
    StdHeader
    );
  S3SaveTablePtr->SaveOffset += OpCodeLength;
  return AGESA_SUCCESS;
}

/*----------------------------------------------------------------------------------------*/
/**
 * Save S3 poll opcode
 *
 *
 *
 * @param[in] StdHeader              Pointer to standard header
 * @param[in] OpCode                  Operation opcode
 * @param[in] InformationLength  Info length
 * @param[in] Information             Pointer to information
 */
AGESA_STATUS
S3SaveStateSaveInfoOp (
  IN      AMD_CONFIG_PARAMS   *StdHeader,
  IN      UINT16              OpCode,
  IN      UINT32              InformationLength,
  IN      VOID                *Information
  )
{

  S3_SAVE_TABLE_HEADER    *S3SaveTablePtr;
  S3_INFO_OP_HEADER       *SaveOffsetPtr;
  UINT32                  OpCodeLength;

  AGESA_STATUS            Status;

  Status = S3ScriptGetS3SaveTable (StdHeader, &S3SaveTablePtr);
  if (Status != AGESA_SUCCESS) {
    return Status;
  }
  OpCodeLength = sizeof (S3_INFO_OP_HEADER) + InformationLength;
  if ((S3SaveTablePtr->SaveOffset + OpCodeLength) > S3SaveTablePtr->TableLength) {
    Status = S3SaveStateExtendTableLenth (StdHeader, &S3SaveTablePtr);
    if (Status != AGESA_SUCCESS) {
      return Status;
    }
  }

  SaveOffsetPtr = (S3_INFO_OP_HEADER *) ((UINT8 *) S3SaveTablePtr + S3SaveTablePtr->SaveOffset);
  SaveOffsetPtr->OpCode = OpCode;
  SaveOffsetPtr->Length = InformationLength;

  LibAmdMemCopy (
    (UINT8 *) SaveOffsetPtr + sizeof (S3_INFO_OP_HEADER),
    Information,
    InformationLength,
    StdHeader
    );
  S3SaveTablePtr->SaveOffset += OpCodeLength;
  return AGESA_SUCCESS;
}
