alder_lake_bios/Intel/AlderLake/AlderLakePlatSamplePkg/Library/BaseEcFlashLib/BaseEcFlashLib.c

568 lines
12 KiB
C

/** @file
@copyright
INTEL CONFIDENTIAL
Copyright 2014 - 2017 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains a 'Sample Driver' and is licensed as such under the terms
of your license agreement with Intel or your vendor. This file may be modified
by the user, subject to the additional terms of the license agreement.
@par Specification Reference:
**/
#include <PiDxe.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseEcFlashLib.h>
#include <Library/DebugLib.h>
////
//
// InByte()
//
// Description: Read a byte from an I/O Port
//
////
#ifdef _MSC_VER
static
UINT32
InByte (
UINT16 Port
)
{
return _inp (Port);
}
#else
#ifdef __GNUC__
static
inline
UINT32
InByte (
UINT16 Port
)
{
UINT8 Data;
__asm__ __volatile__ ( "inb %1, %0;" : "=a"(Data) : "d"(Port) );
return (UINT32) Data;
}
#else
#error Unsupported Compiler
#endif
#endif
////
//
// OutByte()
//
// Description: Write a byte to an I/O Port
//
////
#ifdef _MSC_VER
static
VOID
OutByte (
UINT16 Port,
UINT32 Value
)
{
_outp (Port, Value);
}
#else
#ifdef __GNUC__
static
inline
VOID
OutByte (
UINT16 Port,
UINT32 Value
)
{
__asm__ __volatile__ ( "outb %%al, %1;" : : "a"(Value), "d"(Port) );
}
#else
#error Unsupported Compiler
#endif
#endif
BOOLEAN
IsEcVersionIdentical (
UINT8* pEcBin
)
{
UINT32 ch1, ch2, ch3, ch4;
SendEcCommand(READECREVISION);
ch1 = ReceiveEcData();
ch2 = ReceiveEcData();
DEBUG ((DEBUG_INFO, "\nEC Current Version %X.%02X\n", ch1, ch2));
ch3 = (*(pEcBin+IMAGE_SIGNATURE + 4)); // Ec Major Ver
ch4 = (*(pEcBin+IMAGE_SIGNATURE + 5)); // Ec Minor Ver
DEBUG ((DEBUG_INFO, "\nUpdate to ver %X.%02X\n", ch3, ch4));
// Disallow flasing EC with the same version
if ((ch1 == ch3) && (ch2 == ch4)) {
DEBUG ((DEBUG_INFO, "Same firmware version found!\n"));
return TRUE;
}
return FALSE;
}
EFI_STATUS
EcFlash (
UINT8* pFcntrlBin, UINT32 FcntrlBinSize, UINT8* pEcBin, UINT32 EcBinSize
)
{
UINT32 ch, csum;
UINT32 i, j;
BOOLEAN f = FALSE;
BOOLEAN FlashUpdateComplete; //FcntrlBytes,
VOID *pBuffer = NULL;
UINT64 fSize;
UINT32 Status;
fSize = FcntrlBinSize;
FcntrlLen = fSize;
FcntrlLenLow = (fSize & 0xFF);
FcntrlLenHigh = ((fSize & 0xFF00) >> 8);
// Display the current version
SendEcCommand(READECREVISION);
// Disallow flashing EC with the same version
if (IsEcVersionIdentical(pEcBin)) {
DEBUG ((DEBUG_ERROR, "Skip EC update - same firmware version found!\n"));
return EFI_UNSUPPORTED;
}
//
// Send the "NMI Disable" command to the Ec
//
SendEcCommand(NMIDISABLE);
gBS->Stall (1000); // 1msec
//
// Check if NMI still active
//
if (NmiActive()) {
DEBUG ((DEBUG_ERROR, "\nNMI Detected! Abort flash update."));
return EFI_SUCCESS;
}
//
// Send the "Flash Loader" command to the Ec
//
DEBUG ((DEBUG_INFO, "\nCmd FLASHLOADER"));
SendEcCommand(FLASHLOADER);
//
// Send the size of the flash control file FCNTRL.BIN to the Ec; low byte followed by high byte.
//
DEBUG ((DEBUG_INFO, "\nFcntrlLenLow %x",FcntrlLenLow));
SendEcData(FcntrlLenLow);
DEBUG ((DEBUG_INFO, "\nFcntrlLenHigh %x",FcntrlLenHigh));
SendEcData(FcntrlLenHigh);
//
// Send the flash control file to the Ec.
//
DEBUG ((DEBUG_INFO, "\nSend flash control code"));
gBS->Stall (1000); // ???
csum = 0; // Clear checksum byte
pBuffer = pFcntrlBin;
for (i = 0; i < FcntrlLen; i++) {
//ch = (CHAR16)getc(FcHandle);
ch = (UINT32)(*((UINT8 *)pBuffer + i));
//Print(L"%x", ch);
csum += ch;
ch = ch & 0xFF;
SendEcData(ch);
};
csum = csum & 0xFF;
DEBUG ((DEBUG_INFO, "\nFCNTRL chksm is %X", csum));
ch = ReceiveEcData();
ch = ch & 0xFF;
DEBUG ((DEBUG_INFO, "\nEc computed chksm is %X", ch));
if (ch != csum) {
DEBUG ((DEBUG_ERROR, "\nErr FCNTRL transfer failed SKIP!!!"));
return EFI_SUCCESS; // Check and return error cases.
}
gBS->Stall (100000); // 100ms
DEBUG ((DEBUG_INFO, "\nInit Flash Erase Code"));
SendEcCommand(INITERASE);
ch = ReceiveEcData();
if (ch != 0) {
DEBUG ((DEBUG_ERROR, "\nInit Flash Erase Code FAILED!!! %X", ch));
return EFI_SUCCESS;
}
DEBUG ((DEBUG_INFO, "\nErase flash blk 0 (64K) [00000-0FFFF]..."));
gBS->Stall (100000); // 100ms
EraseFlashBlock(0);
gBS->Stall (500000); // 500ms
DEBUG ((DEBUG_INFO, "\nErase flash blk 1 (64K) [10000-1FFFF]..."));
EraseFlashBlock(1);
gBS->Stall (500000); // 500ms
//
// Load programming and verify code into RAM and check the result
//
DEBUG ((DEBUG_INFO, "\nSend Cmd INITPROGCODE - "));
SendEcCommand(INITPROGCODE);
Status = ReceiveEcData();
if (!(Status & 0xFF)) {
DEBUG ((DEBUG_INFO, "Pass"));
} else {
DEBUG ((DEBUG_INFO, "FAIL!!!"));
return EFI_DEVICE_ERROR;
}
// First program untrusted flash segment. Read the size of the Ec segment
// stored in the image and compute the number of flash blocks to be written.
DEBUG ((DEBUG_INFO, "Calculating EC Bin size\n"));
gBS->Stall (100000); // 100ms
ImageLen = (*((UINT8*)(pEcBin+ECSEGSIZE_OFFSET+2)) << 8) + *((UINT8*)(pEcBin+ECSEGSIZE_OFFSET+3));
DEBUG ((DEBUG_INFO, "Ec bin size: 0x%x\n", ImageLen));
ImageLen = ImageLen/FBLOCK_SIZE + 2;
DEBUG ((DEBUG_INFO, "Blks of Ec bin file: 0x%x\n", ImageLen));
FlashBlock = 0;
//
// Read 128 byte blocks from the input file and program the Ec segment
//
FlashUpdateComplete = FALSE;
pBuffer = pEcBin + EC_SEGMENT;
FecSize = EcBinSize;
i = 0;
while((FlashUpdateComplete == FALSE)&&(FlashBlock < ImageLen )) {
if((i % 128) == 0) {
f = TRUE;
}
FlashBufPtr = FlashBuf; // Point to buffer start.
for (j = 0; j < 128; j++) // Prepad unused buffer locations
*FlashBufPtr++ = 0xFF; // with blank byte.
FlashBufPtr = FlashBuf; // Point to buffer start.
while (((i % 128) != 0) || f) { //(i = 0; i < 128; i++) // Fill buffer from file
f = FALSE;
// until EOF is reached
if(i < FecSize) {
*FlashBufPtr++ = (UINT32)(*((UINT8 *)pBuffer + i));//(CHAR16)getc(InHandle);
i++;
} else {
FlashUpdateComplete = TRUE;
break;
}
}//for
FlashBufPtr = FlashBuf; // Point to buffer starting address.
WriteFlashBlock(FlashBufPtr); // Program buffer into flash.
gBS->Stall (10000); // 10ms
FlashBlock++; // Repeat for all blocks.
}//while
DEBUG ((DEBUG_INFO, "\nFlash programming complete!"));
return EFI_SUCCESS; //exit(0);
}
VOID EcReset (
VOID
)
{
DEBUG ((DEBUG_INFO, "\nSend Ec Reset Cmd!"));
SendEcCommand(RESETEC);
gBS->Stall (2000000); // 2sec
DEBUG ((DEBUG_INFO, "\nPending Reset after 2Sec Ec Reset! "));
return;
}
////
//
// ComputeBuffChksum()
//
// Description: Computes the byte checksum of a binary buffer
//
////
UINT32 ComputeBuffChksum(UINT32 *BufPtr, UINT32 BufSize)
{
UINT32 i;
UINT32 sum = 0;
for (i = 0; i < BufSize; i++)
sum += *BufPtr++;
return (0 - sum);
}
////
//
// WaitInputBufferEmpty()
//
// Description: Waits forever for IBF flag to clear.
//
////
void WaitInputBufferEmpty(void) {
UINT32 Status;
UINTN Count;
Count = 0;
Status = 0;
DEBUG ((DEBUG_INFO, "\nWaitInputBufferEmpty"));
Status = InByte (ECSTATUSPORT);
while (((Status & EC_S_IBF) != 0)) { // && (Count < EC_TIME_OUT)) {
//gBS->Stall (EC_STALL_TIME_OUT);
Status = InByte (ECSTATUSPORT);
Count++;
}
DEBUG ((DEBUG_INFO, "- Exit; Counter=0x%x", Count));
}
////
//
// WaitOutputBufferFull()
//
// Description: Waits forever for OBF flag to set.
//
////
void WaitOutputBufferFull(void)
{
UINT32 Status;
UINTN Count;
Count = 0;
Status = 0;
DEBUG ((DEBUG_INFO, "\nWaitOutputBufferFull"));
Status = InByte (ECSTATUSPORT);
while (((Status & EC_S_OBF) == 0)){ // && (Count < EC_TIME_OUT)) {
//gBS->Stall (EC_STALL_TIME_OUT);
Status = InByte (ECSTATUSPORT);
Count++;
}
DEBUG ((DEBUG_ERROR, "-Exit; Counter=0x%x",Count));
}
////
//
// SendEcCommand()
//
// Description: Send a command to the Ec
//
////
void SendEcCommand(UINT32 CmdNum) {
DEBUG ((DEBUG_INFO, "\nSend Ec Cmd %x", CmdNum));
WaitInputBufferEmpty();
OutByte (ECCOMMANDPORT, CmdNum);
}
////
//
// SendEcData()
//
// Description: Send a Data to the Ec
//
////
void SendEcData(UINT32 CmdNum)
{
DEBUG ((DEBUG_INFO, "\nSend Ec Data %x",CmdNum));
WaitInputBufferEmpty();
OutByte (ECDATAPORT, CmdNum);
}
////
//
// ReceiveEcData()
//
// Description: Get the data returned by the Ec
//
////
UINT32 ReceiveEcData (
VOID
)
{
UINT32 Data;
WaitOutputBufferFull();
Data = InByte (ECDATAPORT);
DEBUG ((DEBUG_INFO, "\nReceive Ec Data 0x%x", Data));
return (Data & 0xFF);
}
////
//
// ReadEcRegister
//
// Description: Returns the Ec register content
//
////
VOID
ReadEcRegister(
IN UINT8 Reg,
OUT UINT8 *RetValue
)
{
SendEcCommand((UINT32) READECMEM);
SendEcData(Reg);
*RetValue = (UINT8) ReceiveEcData ();
}
////
//
// NmiActive()
//
// Description: Returns true if NMI is active.
//
////
UINT32 NmiActive(void)
{
SendEcCommand(GETSWITCHSTATUS);
return (ReceiveEcData() & BIT2);
}
////
//
// EraseFlashBlock()
//
////
UINT32 EraseFlashBlock(UINT32 BlkNum)
{
UINT32 Status;
DEBUG ((DEBUG_INFO, "\nErasing Ec Blk %x - ", BlkNum));
SendEcCommand(SETERASEBLKNUM);
SendEcData(BlkNum);
SendEcCommand(ERASEFLASHBLK);
Status = ReceiveEcData();
if (Status & 0xFF) {
DEBUG ((DEBUG_INFO, "Fail"));
return EFI_SUCCESS;
} else {
DEBUG ((DEBUG_INFO, "Pass"));
}
return EFI_SUCCESS;
}//EraseFlashBlock
////
//
// WriteFlashBlock()
//
// Description: Writes a 128 byte block of data to the flash.
// Input: FBufPtr -> Data buffer to flash
//
////
UINT32 WriteFlashBlock(UINT32 *FBufPtr)
{
UINT32 i;
UINT32 ch, csum = 0;
UINT32 Data;
DEBUG ((DEBUG_INFO, "\nWriting Ec Flash Block"));
SendEcCommand(LOADFLASHBLK);
DEBUG ((DEBUG_INFO, "\n"));
for (i = 0; i < FBLOCK_SIZE; i++) {
ch = *FBufPtr++;
csum += ch;
ch = ch & 0xFF;
DEBUG ((DEBUG_INFO, "%X", ch));
SendEcData(ch);
}
DEBUG ((DEBUG_INFO, "\n"));
csum = csum & 0xFF;
Data = ReceiveEcData() & 0xFF;
if (Data != csum) {
DEBUG ((DEBUG_INFO, "\nChecksum Calculated/Received is = %X / %X", csum, Data));
return EFI_SUCCESS;
}
FlashBufPtr = FlashBuf; // Point to buffer start.
DEBUG ((DEBUG_INFO, "\nSet Flash Addr"));
SendEcCommand(SETFLASHWRITEADDR);
FBlkStartAddr = FBLOCK_SIZE * FlashBlock;
SendEcData((FBlkStartAddr & 0xFF));
SendEcData(((FBlkStartAddr >> 8 ) & 0xFF));
SendEcData(((FBlkStartAddr >> 16 ) & 0xFF));
DEBUG ((DEBUG_INFO, "\nProgram Flash"));
SendEcCommand(PROGRAMFLASHBLK);
Data = ReceiveEcData();
if (Data) {
DEBUG ((DEBUG_INFO, " - FAIL"));
return EFI_SUCCESS;
} else {
DEBUG ((DEBUG_INFO, " - PASS"));
return EFI_SUCCESS;
}
}//WriteFlashBlock
////
//
// IsBlankBlock()
//
// Description: Returns TRUE if a 128 byte block of data is all FFs
// Input: FBufPtr -> Data buffer to check
//
//
////
CHAR16 IsBlankBlock(CHAR16 *FBPtr)
{
CHAR16 i, ch;
CHAR16 *BPtr;
BPtr = FBPtr;
for (i = 0; i < FBLOCK_SIZE; i++) {
ch = *BPtr++;
if (ch != 0xFF)
return (0x0);
}
return ((!0x0)); // RETURN TRUE;
}