/** @file Base EC library implementation for H/W layer. Copyright (c) 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #ifndef STALL_ONE_MICRO_SECOND #define STALL_ONE_MICRO_SECOND 1 #endif #ifndef STALL_ONE_MILLI_SECOND #define STALL_ONE_MILLI_SECOND 1000 #endif #ifndef EC_INIT_TIME_OUT #define EC_INIT_TIME_OUT 0x200 #endif typedef struct { UINT8 CommandNumber; UINT8 NumberOfSendData; UINT8 NumberOfReceiveData; BOOLEAN CommandImplemented; } EC_COMMAND_TABLE; EC_COMMAND_TABLE mEcCommand[] = { {EC_C_FAB_ID , 0, 2, TRUE}, // Get the board fab ID in the lower 3 bits {EC_C_ACPI_READ , 1, 1, TRUE}, // Read a byte of EC RAM {EC_C_ACPI_WRITE , 2, 0, TRUE} // Write a byte of EC RAM }; // // Function implementations // /** Sends command to EC. @param[in] Command Command byte to send @param[in] Timeout Timeout in microseonds @retval EFI_SUCCESS Command success @retval EFI_DEVICE_ERROR Command error @retval EFI_TIMEOUT Command timeout **/ EFI_STATUS SendEcCommandTimeout ( IN UINT8 Command, IN UINT32 Timeout ) { UINTN Index; UINT8 EcStatus; UINT8 DiscardData; Index = 0; EcStatus = 0; DiscardData = 0; // // Wait for EC to be ready (with a timeout) // ReceiveEcStatus (&EcStatus); // // Check if output buffer bit(OBF) is set. // Read and discard the output buffer data so that next BIOS-EC cmd is in sync // OBF is cleared by h/w after all data in output buffer is read by BIOS. // while ((EcStatus & EC_S_OBF) != 0) { // // Read EC data // DiscardData = IoRead8 (EC_D_PORT); DEBUG ((DEBUG_INFO, "OBF is Set!! DiscardData Read 0x%02X\n", DiscardData)); ReceiveEcStatus (&EcStatus); } while (((EcStatus & EC_S_IBF) != 0) && (Index < Timeout)) { MicroSecondDelay (15 * STALL_ONE_MICRO_SECOND); ReceiveEcStatus (&EcStatus); Index++; } if (Index >= Timeout) { return EFI_TIMEOUT; } //Printing EC Command Sent DEBUG ((DEBUG_INFO, "Sending EC Command: %02X\n", Command)); // // Send the EC command // IoWrite8 (EC_C_PORT, Command); return EFI_SUCCESS; } /** Sends command to EC. @param[in] Command Command byte to send @retval EFI_SUCCESS Command success @retval EFI_DEVICE_ERROR Command error @retval EFI_TIMEOUT Command timeout **/ EFI_STATUS SendEcCommand ( IN UINT8 Command ) { return SendEcCommandTimeout (Command, EC_TIME_OUT); } /** Receives status from EC. @param[out] EcStatus Status byte to receive @retval EFI_SUCCESS @retval EFI_DEVICE_ERROR **/ EFI_STATUS ReceiveEcStatus ( OUT UINT8 *EcStatus ) { // // Read and return the status // *EcStatus = IoRead8 (EC_C_PORT); return EFI_SUCCESS; } /** Sends data to EC. @param[in] Data Data byte to send @retval EFI_SUCCESS @retval EFI_DEVICE_ERROR **/ EFI_STATUS SendEcData ( IN UINT8 Data ) { UINTN Index; UINT8 EcStatus; Index = 0; // // Wait for EC to be ready (with a timeout) // ReceiveEcStatus (&EcStatus); while (((EcStatus & EC_S_IBF) != 0) && (Index < EC_TIME_OUT)) { MicroSecondDelay (15); ReceiveEcStatus (&EcStatus); Index++; } if (Index >= EC_TIME_OUT) { return EFI_DEVICE_ERROR; } // //Printing EC Data Sent // DEBUG ((DEBUG_INFO, "Sending EC Data: %02X\n", Data)); // // Send the data and return // IoWrite8 (EC_D_PORT, Data); return EFI_SUCCESS; } /** Receives data from EC. @param[out] Data Data byte received @param[in] Timeout Timeout in microseonds @retval EFI_SUCCESS Read success @retval EFI_DEVICE_ERROR Read error @retval EFI_TIMEOUT Command timeout --*/ EFI_STATUS ReceiveEcDataTimeout ( OUT UINT8 *Data, IN UINT32 Timeout ) { UINTN Index; UINT8 EcStatus; Index = 0; // // Wait for EC to be ready (with a timeout) // ReceiveEcStatus (&EcStatus); while (((EcStatus & EC_S_OBF) == 0) && (Index < Timeout)) { MicroSecondDelay (15 * STALL_ONE_MICRO_SECOND); ReceiveEcStatus (&EcStatus); Index++; } if (Index >= Timeout) { return EFI_TIMEOUT; } // // Read EC data and return // *Data = IoRead8 (EC_D_PORT); //Printing EC Data Received DEBUG ((DEBUG_INFO, "Receiving EC Data: %02X\n", *Data)); return EFI_SUCCESS; } /** Receives data from EC. @param[out] Data Data byte received @retval EFI_SUCCESS Read success @retval EFI_DEVICE_ERROR Read error @retval EFI_TIMEOUT Command timeout **/ EFI_STATUS ReceiveEcData ( OUT UINT8 *Data ) { return ReceiveEcDataTimeout (Data, EC_TIME_OUT); } /** Send data to EC through LPC interface. @param[in] Command Command value to send to the EC @param[in][out] DataSize Size of data to send to the EC. If the command retuned data - size of buffer returned by the EC. Be aware of the DataSize must euqal to size of DataBuffer and cannot smaller than number of send data or number of receive data, whichever is the grater. @param[in][out] DataBuffer Pointer to the data buffer including data to be sent to the EC. If the command returned data - pointer to the buffer including the data. The buffer size should be the max of receive and transmit data. @retval EFI_SUCCESS Success @retval Other Failed - EFI_TIMEOUT, EFI_INVALID_PARAMETER, EFI_UNSUPPORTED, EFI_BUFFER_TOO_SMALL, etc. **/ EFI_STATUS LpcEcInterface ( IN UINT8 Command, IN OUT UINT8 *DataSize, IN OUT UINT8 *DataBuffer ) { EFI_STATUS Status; UINT8 NumberOfEcCommands; UINT8 Index; UINT8 TxDataIndex; UINT8 RxDataIndex; UINT8 MaxValue; Status = EFI_SUCCESS; NumberOfEcCommands = sizeof (mEcCommand) / sizeof (EC_COMMAND_TABLE); for (Index = 0; Index < NumberOfEcCommands; Index++) { if (Command != mEcCommand[Index].CommandNumber) { continue; } if (mEcCommand[Index].CommandImplemented != TRUE) { Status = EFI_UNSUPPORTED; break; } if ((mEcCommand[Index].NumberOfSendData != 0) || (mEcCommand[Index].NumberOfReceiveData != 0)) { if (DataSize == NULL || DataBuffer == NULL) { Status = EFI_INVALID_PARAMETER; break; } else { MaxValue = MAX (mEcCommand[Index].NumberOfSendData, mEcCommand[Index].NumberOfReceiveData); if (*DataSize < MaxValue) { Status = EFI_BUFFER_TOO_SMALL; *DataSize = MaxValue; break; } } } Status = SendEcCommand (Command); if (EFI_ERROR (Status)) { break; } if (mEcCommand[Index].NumberOfSendData != 0) { for (TxDataIndex = 0; TxDataIndex < mEcCommand[Index].NumberOfSendData; TxDataIndex++) { Status = SendEcData (DataBuffer[TxDataIndex]); if (EFI_ERROR (Status)) { break; } } } if (mEcCommand[Index].NumberOfReceiveData != 0) { for (RxDataIndex = 0; RxDataIndex < mEcCommand[Index].NumberOfReceiveData; RxDataIndex++) { Status = ReceiveEcData (&DataBuffer[RxDataIndex]); if (EFI_ERROR (Status)) { break; } *DataSize = RxDataIndex + 1; } } break; } return Status; }