mirror of https://github.com/acidanthera/audk.git
258 lines
7.1 KiB
C
258 lines
7.1 KiB
C
|
/** @file
|
||
|
|
||
|
Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||
|
|
||
|
This program and the accompanying materials
|
||
|
are licensed and made available under the terms and conditions of the BSD License
|
||
|
which accompanies this distribution. The full text of the license may be found at
|
||
|
http://opensource.org/licenses/bsd-license.php
|
||
|
|
||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||
|
|
||
|
System Control and Management Interface V1.0
|
||
|
http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/
|
||
|
DEN0056A_System_Control_and_Management_Interface.pdf
|
||
|
**/
|
||
|
|
||
|
#include <Library/ArmMtlLib.h>
|
||
|
#include <Library/DebugLib.h>
|
||
|
#include <Library/MemoryAllocationLib.h>
|
||
|
#include <Library/UefiBootServicesTableLib.h>
|
||
|
|
||
|
#include "ScmiPrivate.h"
|
||
|
|
||
|
// Arbitrary timeout value 20ms.
|
||
|
#define RESPONSE_TIMEOUT 20000
|
||
|
|
||
|
/** Return a pointer to the message payload.
|
||
|
|
||
|
@param[out] Payload Holds pointer to the message payload.
|
||
|
|
||
|
@retval EFI_SUCCESS Payload holds a valid message payload pointer.
|
||
|
@retval EFI_TIMEOUT Time out error if MTL channel is busy.
|
||
|
@retval EFI_UNSUPPORTED If MTL channel is unsupported.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
ScmiCommandGetPayload (
|
||
|
OUT UINT32** Payload
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
MTL_CHANNEL *Channel;
|
||
|
|
||
|
// Get handle to the Channel.
|
||
|
Status = MtlGetChannel (MTL_CHANNEL_TYPE_LOW, &Channel);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Payload will not be populated until channel is free.
|
||
|
Status = MtlWaitUntilChannelFree (Channel, RESPONSE_TIMEOUT);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Get the address of the payload.
|
||
|
*Payload = MtlGetChannelPayload (Channel);
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/** Execute a SCMI command and receive a response.
|
||
|
|
||
|
This function uses a MTL channel to transfer message to SCP
|
||
|
and waits for a response.
|
||
|
|
||
|
@param[in] Command Pointer to the SCMI command (Protocol ID
|
||
|
and Message ID)
|
||
|
|
||
|
@param[in,out] PayloadLength SCMI command message length.
|
||
|
|
||
|
@param[out] OPTIONAL ReturnValues Pointer to SCMI response.
|
||
|
|
||
|
@retval OUT EFI_SUCCESS Command sent and message received successfully.
|
||
|
@retval OUT EFI_UNSUPPORTED Channel not supported.
|
||
|
@retval OUT EFI_TIMEOUT Timeout on the channel.
|
||
|
@retval OUT EFI_DEVICE_ERROR Channel not ready.
|
||
|
@retval OUT EFI_DEVICE_ERROR Message Header corrupted.
|
||
|
@retval OUT EFI_DEVICE_ERROR SCMI error.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
ScmiCommandExecute (
|
||
|
IN SCMI_COMMAND *Command,
|
||
|
IN OUT UINT32 *PayloadLength,
|
||
|
OUT UINT32 **ReturnValues OPTIONAL
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
SCMI_MESSAGE_RESPONSE *Response;
|
||
|
UINT32 MessageHeader;
|
||
|
UINT32 ResponseHeader;
|
||
|
MTL_CHANNEL *Channel;
|
||
|
|
||
|
ASSERT (PayloadLength != NULL);
|
||
|
|
||
|
Status = MtlGetChannel (MTL_CHANNEL_TYPE_LOW, &Channel);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Fill in message header.
|
||
|
MessageHeader = SCMI_MESSAGE_HEADER (
|
||
|
Command->MessageId,
|
||
|
SCMI_MESSAGE_TYPE_COMMAND,
|
||
|
Command->ProtocolId
|
||
|
);
|
||
|
|
||
|
// Send payload using MTL channel.
|
||
|
Status = MtlSendMessage (
|
||
|
Channel,
|
||
|
MessageHeader,
|
||
|
*PayloadLength
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Wait for the response on the channel.
|
||
|
Status = MtlReceiveMessage (Channel, &ResponseHeader, PayloadLength);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// SCMI must return MessageHeader unmodified.
|
||
|
if (MessageHeader != ResponseHeader) {
|
||
|
ASSERT (FALSE);
|
||
|
return EFI_DEVICE_ERROR;
|
||
|
}
|
||
|
|
||
|
Response = (SCMI_MESSAGE_RESPONSE*)MtlGetChannelPayload (Channel);
|
||
|
|
||
|
if (Response->Status != SCMI_SUCCESS) {
|
||
|
DEBUG ((DEBUG_ERROR, "SCMI error: ProtocolId = 0x%x, MessageId = 0x%x, error = %d\n",
|
||
|
Command->ProtocolId,
|
||
|
Command->MessageId,
|
||
|
Response->Status
|
||
|
));
|
||
|
|
||
|
ASSERT (FALSE);
|
||
|
return EFI_DEVICE_ERROR;
|
||
|
}
|
||
|
|
||
|
if (ReturnValues != NULL) {
|
||
|
*ReturnValues = Response->ReturnValues;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/** Internal common function useful for common protocol discovery messages.
|
||
|
|
||
|
@param[in] ProtocolId Protocol Id of the the protocol.
|
||
|
@param[in] MesaageId Message Id of the message.
|
||
|
|
||
|
@param[out] ReturnValues SCMI response return values.
|
||
|
|
||
|
@retval EFI_SUCCESS Success with valid return values.
|
||
|
@retval EFI_DEVICE_ERROR SCMI error.
|
||
|
@retval !(EFI_SUCCESS) Other errors.
|
||
|
**/
|
||
|
STATIC
|
||
|
EFI_STATUS
|
||
|
ScmiProtocolDiscoveryCommon (
|
||
|
IN SCMI_PROTOCOL_ID ProtocolId,
|
||
|
IN SCMI_MESSAGE_ID MessageId,
|
||
|
OUT UINT32 **ReturnValues
|
||
|
)
|
||
|
{
|
||
|
SCMI_COMMAND Command;
|
||
|
UINT32 PayloadLength = 0;
|
||
|
|
||
|
Command.ProtocolId = ProtocolId;
|
||
|
Command.MessageId = MessageId;
|
||
|
|
||
|
return ScmiCommandExecute (
|
||
|
&Command,
|
||
|
&PayloadLength,
|
||
|
ReturnValues
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/** Return protocol version from SCP for a given protocol ID.
|
||
|
|
||
|
@param[in] Protocol ID Protocol ID.
|
||
|
@param[out] Version Pointer to version of the protocol.
|
||
|
|
||
|
@retval EFI_SUCCESS Version holds a valid version received
|
||
|
from the SCP.
|
||
|
@retval EFI_DEVICE_ERROR SCMI error.
|
||
|
@retval !(EFI_SUCCESS) Other errors.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
ScmiGetProtocolVersion (
|
||
|
IN SCMI_PROTOCOL_ID ProtocolId,
|
||
|
OUT UINT32 *Version
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINT32 *ProtocolVersion;
|
||
|
|
||
|
Status = ScmiProtocolDiscoveryCommon (
|
||
|
ProtocolId,
|
||
|
SCMI_MESSAGE_ID_PROTOCOL_VERSION,
|
||
|
(UINT32**)&ProtocolVersion
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
*Version = *ProtocolVersion;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/** Return protocol attributes from SCP for a given protocol ID.
|
||
|
|
||
|
@param[in] Protocol ID Protocol ID.
|
||
|
@param[out] ReturnValues Pointer to attributes of the protocol.
|
||
|
|
||
|
@retval EFI_SUCCESS ReturnValues points to protocol attributes.
|
||
|
@retval EFI_DEVICE_ERROR SCMI error.
|
||
|
@retval !(EFI_SUCCESS) Other errors.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
ScmiGetProtocolAttributes (
|
||
|
IN SCMI_PROTOCOL_ID ProtocolId,
|
||
|
OUT UINT32 **ReturnValues
|
||
|
)
|
||
|
{
|
||
|
return ScmiProtocolDiscoveryCommon (
|
||
|
ProtocolId,
|
||
|
SCMI_MESSAGE_ID_PROTOCOL_ATTRIBUTES,
|
||
|
ReturnValues
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/** Return protocol message attributes from SCP for a given protocol ID.
|
||
|
|
||
|
@param[in] Protocol ID Protocol ID.
|
||
|
@param[out] Attributes Pointer to attributes of the protocol.
|
||
|
|
||
|
@retval EFI_SUCCESS ReturnValues points to protocol message attributes.
|
||
|
@retval EFI_DEVICE_ERROR SCMI error.
|
||
|
@retval !(EFI_SUCCESS) Other errors.
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
ScmiGetProtocolMessageAttributes (
|
||
|
IN SCMI_PROTOCOL_ID ProtocolId,
|
||
|
OUT UINT32 **ReturnValues
|
||
|
)
|
||
|
{
|
||
|
return ScmiProtocolDiscoveryCommon (
|
||
|
ProtocolId,
|
||
|
SCMI_MESSAGE_ID_PROTOCOL_MESSAGE_ATTRIBUTES,
|
||
|
ReturnValues
|
||
|
);
|
||
|
}
|