summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c')
-rw-r--r--ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c b/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c
new file mode 100644
index 0000000..91a8614
--- /dev/null
+++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c
@@ -0,0 +1,291 @@
+/** @file
+ PCH Smbus PEIM. This file is used when we want ARP support.
+
+@copyright
+ Copyright (c) 2009 - 2012 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#include "PchSmbus.h"
+
+static EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEndOfPeiSignalPpiGuid,
+ EndOfPeiCallback
+};
+
+EFI_GUID mEfiSmbusArpMapGuid = EFI_SMBUS_ARP_MAP_GUID;
+
+/**
+ Set Slave address for an Smbus device with a known UDID or perform a general
+ ARP of all devices.
+
+ @param[in] PeiServices Pointer to the PEI Services table.
+ @param[in] This Pointer to the instance of the PEI_SMBUS_PPI.
+ @param[in] ArpAll If TRUE, do a full ARP. Otherwise, just ARP the specified UDID.
+ @param[in] SmbusUdid When doing a directed ARP, ARP the device with this UDID.
+ @param[in, out] SlaveAddress Buffer to store new Slave Address during directed ARP.
+
+ @exception EFI_UNSUPPORTED This functionality is not supported
+ @retval EFI_SUCCESS The function completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmbusArpDevice (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_SMBUS_PPI * This,
+ IN BOOLEAN ArpAll,
+ IN EFI_SMBUS_UDID * SmbusUdid OPTIONAL,
+ IN OUT EFI_SMBUS_DEVICE_ADDRESS * SlaveAddress OPTIONAL
+ )
+{
+ SMBUS_INSTANCE *Private;
+ EFI_STATUS Status;
+ UINT8 OldMapEntries;
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusArpDevice() Start\n"));
+
+ Private = SMBUS_PRIVATE_DATA_FROM_PPI_THIS (This);
+
+ OldMapEntries = Private->DeviceMapEntries;
+
+ if (ArpAll) {
+ Status = SmbusFullArp (Private);
+ } else {
+ if ((SmbusUdid == NULL) || (SlaveAddress == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = SmbusDirectedArp (Private, SmbusUdid, SlaveAddress);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ///
+ /// If we just added the first entry in the device map, set up a callback so
+ /// we can pass the map to DXE via a HOB at the end of PEI.
+ ///
+ if ((OldMapEntries == 0) && (Private->DeviceMapEntries > 0)) {
+ Status = (**PeiServices).NotifyPpi (PeiServices, &mNotifyList);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusArpDevice() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get a pointer to the assigned mappings of UDID's to Slave Addresses.
+
+ @param[in] PeiServices Pointer to the PEI Services table.
+ @param[in] This Pointer to the instance of the PEI_SMBUS_PPI.
+ @param[in, out] Length Buffer to contain the lenght of the Device Map.
+ @param[in, out] SmbusDeviceMap Buffer to contian a pointer to the Device Map.
+
+ @exception EFI_UNSUPPORTED This functionality is not supported
+ @retval EFI_SUCCESS The function completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmbusGetArpMap (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_SMBUS_PPI *This,
+ IN OUT UINTN *Length,
+ IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap
+ )
+{
+ SMBUS_INSTANCE *Private;
+
+ Private = SMBUS_PRIVATE_DATA_FROM_PPI_THIS (This);
+
+ *Length = Private->DeviceMapEntries * sizeof (EFI_SMBUS_DEVICE_MAP);
+ *SmbusDeviceMap = Private->DeviceMap;
+ return EFI_SUCCESS;
+}
+
+/**
+ Register a callback in the event of a Host Notify command being sent by a
+ specified Slave Device.
+
+ @param[in] PeiServices The general PEI Services
+ @param[in] This The PPI instance
+ @param[in] SlaveAddress Address of the device whose Host Notify command we want to trap.
+ @param[in] Data Data of the Host Notify command we want to trap.
+ @param[in] NotifyFunction Function to be called in the event the desired Host Notify command occurs.
+
+ @exception EFI_UNSUPPORTED This functionality is not supported
+ @retval EFI_SUCCESS The function completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmbusNotify (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_SMBUS_PPI *This,
+ IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
+ IN UINTN Data,
+ IN EFI_PEI_SMBUS_NOTIFY_FUNCTION NotifyFunction
+ )
+{
+ SMBUS_INSTANCE *Private;
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusNotify() Start\n"));
+
+ Private = SMBUS_PRIVATE_DATA_FROM_PPI_THIS (This);
+
+ if (NotifyFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ ///
+ /// NOTE: Currently there is no periodic event in PEI.
+ /// So we just check the Notification at the end of in each
+ /// Smbus.Execute function.
+ ///
+ if (Private->NotifyFunctionNum >= MAX_SMBUS_NOTIFICATION) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->NotifyFunctionList[Private->NotifyFunctionNum].SlaveAddress.SmbusDeviceAddress = SlaveAddress.SmbusDeviceAddress;
+ Private->NotifyFunctionList[Private->NotifyFunctionNum].Data = Data;
+ Private->NotifyFunctionList[Private->NotifyFunctionNum].NotifyFunction = NotifyFunction;
+ Private->NotifyFunctionNum++;
+
+ ///
+ /// Last step, check notification
+ ///
+ CheckNotification (Private);
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusNotify() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function gets called back at the end of PEI if any devices were ARPed
+ during PEI. It will build a HOB to describe to DXE what devices were ARPed.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] NotifyDescriptor The notification structure this PEIM registered on install.
+ @param[in] Ppi The EndOfPeiSignal PPI.
+
+ @retval EFI_SUCCESS The function completed successfully.
+**/
+EFI_STATUS
+EndOfPeiCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PPI_DESCRIPTOR *SmbusDescriptor;
+ PEI_SMBUS_PPI *SmbusPpi;
+ SMBUS_INSTANCE *Private;
+ UINTN BufferSize;
+ VOID *Hob;
+
+ DEBUG ((EFI_D_INFO, "PEI EndOfPeiCallback() Start\n"));
+
+ Status = (**PeiServices).LocatePpi (
+ PeiServices,
+ &gPeiSmbusPpiGuid, /// GUID
+ 0, /// INSTANCE
+ &SmbusDescriptor, /// PEI_PPI_DESCRIPTOR
+ &SmbusPpi /// PPI
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Private = SMBUS_PRIVATE_DATA_FROM_DESCRIPTOR_THIS (SmbusDescriptor);
+ BufferSize = sizeof (EFI_SMBUS_DEVICE_MAP) * Private->DeviceMapEntries;
+
+ Hob = BuildGuidDataHob (
+ &mEfiSmbusArpMapGuid,
+ Private->DeviceMap,
+ BufferSize
+ );
+ ASSERT (Hob != NULL);
+
+ DEBUG ((EFI_D_INFO, "PEI EndOfPeiCallback() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to be called when SMBus.Execute happens. This will check if
+ the SMBus Host Controller has received a Host Notify command. If so, it will
+ see if a notification has been reqested on that event and make any callbacks
+ that may be necessary.
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+
+ @retval None
+**/
+VOID
+CheckNotification (
+ IN SMBUS_INSTANCE *Private
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ UINT8 SstsReg;
+ UINTN Data;
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "PEI CheckNotification() Start\n"));
+
+ if (Private->NotifyFunctionNum == 0) {
+ ///
+ /// Since no one register it, not need to check.
+ ///
+ return;
+ }
+
+ SstsReg = SmbusIoRead (R_PCH_SMBUS_SSTS);
+ if (!(SstsReg & B_PCH_SMBUS_HOST_NOTIFY_STS)) {
+ ///
+ /// Host Notify has not been received
+ ///
+ return;
+ }
+ ///
+ /// There was a Host Notify, see if any one wants to know about it
+ ///
+ SlaveAddress.SmbusDeviceAddress = (SmbusIoRead (R_PCH_SMBUS_NDA)) >> 1;
+
+ for (Index = 0; Index < Private->NotifyFunctionNum; Index++) {
+
+ if (Private->NotifyFunctionList[Index].SlaveAddress.SmbusDeviceAddress == SlaveAddress.SmbusDeviceAddress) {
+ Data = (SmbusIoRead (R_PCH_SMBUS_NDHB) << 8) + (SmbusIoRead (R_PCH_SMBUS_NDLB));
+ if ((UINT16) Private->NotifyFunctionList[Index].Data == (UINT16) Data) {
+ ///
+ /// We have a match, notify the requested function
+ ///
+ Private->NotifyFunctionList[Index].NotifyFunction (
+ Private->PeiServices,
+ &Private->SmbusPpi,
+ SlaveAddress,
+ Data
+ );
+ }
+ }
+ }
+ ///
+ /// Clear the Notify Status bit and exit.
+ ///
+ SmbusIoWrite (R_PCH_SMBUS_SSTS, B_PCH_SMBUS_HOST_NOTIFY_STS);
+
+ DEBUG ((EFI_D_INFO, "PEI CheckNotification() End\n"));
+}