summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArp.c')
-rw-r--r--ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArp.c444
1 files changed, 444 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArp.c b/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArp.c
new file mode 100644
index 0000000..9ba5647
--- /dev/null
+++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArp.c
@@ -0,0 +1,444 @@
+/** @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"
+
+///
+/// These addresses are reserved by the SMBus 2.0 specification
+///
+static UINT8 mReservedAddress[SMBUS_NUM_RESERVED] = {
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x06,
+ 0x08,
+ 0x0A,
+ 0x0C,
+ 0x0E,
+ 0x10,
+ 0x18,
+ 0x50,
+ 0x6E,
+ 0xC2,
+ 0xF0,
+ 0xF2,
+ 0xF4,
+ 0xF6,
+ 0xF8,
+ 0xFA,
+ 0xFC,
+ 0xFE,
+ 0x12,
+ 0x14,
+ 0x16,
+ 0x58,
+ 0x5A,
+ 0x80,
+ 0x82,
+ 0x84,
+ 0x86,
+ 0x88,
+ 0x90,
+ 0x92,
+ 0x94,
+ 0x96,
+ 0x1A,
+ 0x1C,
+ 0x1E
+};
+
+/**
+ Issue a prepare ARP command to informs all devices that the ARP Master is starting the ARP process
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SmbusPrepareToArp (
+ IN SMBUS_INSTANCE *Private
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ EFI_STATUS Status;
+ UINTN Length;
+ UINT8 Buffer;
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusPrepareToArp() Start\n"));
+
+ SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
+ Length = 1;
+ Buffer = SMBUS_DATA_PREPARE_TO_ARP;
+
+ Status = SmbusExec (
+ SlaveAddress,
+ 0,
+ EfiSmbusSendByte,
+ TRUE,
+ &Length,
+ &Buffer
+ );
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusPrepareToArp() End\n"));
+
+ return Status;
+}
+
+/**
+ Issue a Get UDID (general) command to requests ARP-capable and/or Discoverable devices to
+ return their slave address along with their UDID.
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+ @param[in, out] DeviceMap Pointer to SMBUS device map table that slave device return
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SmbusGetUdidGeneral (
+ IN SMBUS_INSTANCE *Private,
+ IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ EFI_STATUS Status;
+ UINTN Length;
+ UINT8 Buffer[SMBUS_GET_UDID_LENGTH];
+
+ SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
+ Length = SMBUS_GET_UDID_LENGTH;
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusGetUdidGeneral() Start\n"));
+
+ Status = SmbusExec (
+ SlaveAddress,
+ SMBUS_DATA_GET_UDID_GENERAL,
+ EfiSmbusReadBlock,
+ TRUE,
+ &Length,
+ Buffer
+ );
+
+ if (!EFI_ERROR (Status)) {
+ if (Length == SMBUS_GET_UDID_LENGTH) {
+ DeviceMap->SmbusDeviceUdid.DeviceCapabilities = Buffer[0];
+ DeviceMap->SmbusDeviceUdid.VendorRevision = Buffer[1];
+ DeviceMap->SmbusDeviceUdid.VendorId = (UINT16) ((Buffer[2] << 8) + Buffer[3]);
+ DeviceMap->SmbusDeviceUdid.DeviceId = (UINT16) ((Buffer[4] << 8) + Buffer[5]);
+ DeviceMap->SmbusDeviceUdid.Interface = (UINT16) ((Buffer[6] << 8) + Buffer[7]);
+ DeviceMap->SmbusDeviceUdid.SubsystemVendorId = (UINT16) ((Buffer[8] << 8) + Buffer[9]);
+ DeviceMap->SmbusDeviceUdid.SubsystemDeviceId = (UINT16) ((Buffer[10] << 8) + Buffer[11]);
+ DeviceMap->SmbusDeviceUdid.VendorSpecificId = (UINT32) ((Buffer[12] << 24) + (Buffer[13] << 16) + (Buffer[14] << 8) + Buffer[15]);
+ DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress = (UINT8) (Buffer[16] >> 1);
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusGetUdidGeneral() End\n"));
+
+ return Status;
+}
+
+/**
+ Issue a Assign address command to assigns an address to a specific slave device.
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+ @param[in, out] DeviceMap Pointer to SMBUS device map table that send to slave device
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SmbusAssignAddress (
+ IN SMBUS_INSTANCE *Private,
+ IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap
+ )
+{
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ EFI_STATUS Status;
+ UINTN Length;
+ UINT8 Buffer[SMBUS_GET_UDID_LENGTH];
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusAssignAddress() Start\n"));
+
+ Buffer[0] = DeviceMap->SmbusDeviceUdid.DeviceCapabilities;
+ Buffer[1] = DeviceMap->SmbusDeviceUdid.VendorRevision;
+ Buffer[2] = (UINT8) (DeviceMap->SmbusDeviceUdid.VendorId >> 8);
+ Buffer[3] = (UINT8) (DeviceMap->SmbusDeviceUdid.VendorId);
+ Buffer[4] = (UINT8) (DeviceMap->SmbusDeviceUdid.DeviceId >> 8);
+ Buffer[5] = (UINT8) (DeviceMap->SmbusDeviceUdid.DeviceId);
+ Buffer[6] = (UINT8) (DeviceMap->SmbusDeviceUdid.Interface >> 8);
+ Buffer[7] = (UINT8) (DeviceMap->SmbusDeviceUdid.Interface);
+ Buffer[8] = (UINT8) (DeviceMap->SmbusDeviceUdid.SubsystemVendorId >> 8);
+ Buffer[9] = (UINT8) (DeviceMap->SmbusDeviceUdid.SubsystemVendorId);
+ Buffer[10] = (UINT8) (DeviceMap->SmbusDeviceUdid.SubsystemDeviceId >> 8);
+ Buffer[11] = (UINT8) (DeviceMap->SmbusDeviceUdid.SubsystemDeviceId);
+ Buffer[12] = (UINT8) (DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 24);
+ Buffer[13] = (UINT8) (DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 16);
+ Buffer[14] = (UINT8) (DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 8);
+ Buffer[15] = (UINT8) (DeviceMap->SmbusDeviceUdid.VendorSpecificId);
+ Buffer[16] = (UINT8) (DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress << 1);
+
+ SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
+ Length = SMBUS_GET_UDID_LENGTH;
+
+ Status = SmbusExec (
+ SlaveAddress,
+ SMBUS_DATA_ASSIGN_ADDRESS,
+ EfiSmbusWriteBlock,
+ TRUE,
+ &Length,
+ Buffer
+ );
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusAssignAddress() End\n"));
+
+ return Status;
+}
+
+/**
+ Do a fully (general) Arp procress to assign the slave address of all ARP-capable device.
+ This function will issue issue the "Prepare to ARP", "Get UDID" and "Assign Address" commands.
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+
+ @retval EFI_OUT_OF_RESOURCES No available address to assign
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SmbusFullArp (
+ IN SMBUS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap;
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusFullArp() Start\n"));
+
+ Status = SmbusPrepareToArp (Private);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_DEVICE_ERROR) {
+ ///
+ /// ARP is complete
+ ///
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+ }
+ ///
+ /// Main loop to ARP all ARP-capable devices
+ ///
+ do {
+ CurrentDeviceMap = &Private->DeviceMap[Private->DeviceMapEntries];
+ Status = SmbusGetUdidGeneral (Private, CurrentDeviceMap);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress == (0xFF >> 1)) {
+ ///
+ /// If address is unassigned, assign it
+ ///
+ Status = GetNextAvailableAddress (
+ Private,
+ &CurrentDeviceMap->SmbusDeviceAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (((CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities) & 0xC0) != 0) {
+ ///
+ /// if address is not fixed, check if the current address is available
+ ///
+ if (!IsAddressAvailable (
+ Private,
+ CurrentDeviceMap->SmbusDeviceAddress
+ )) {
+ ///
+ /// if currently assigned address is already used, get a new one
+ ///
+ Status = GetNextAvailableAddress (
+ Private,
+ &CurrentDeviceMap->SmbusDeviceAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+
+ Status = SmbusAssignAddress (Private, CurrentDeviceMap);
+ if (EFI_ERROR (Status)) {
+ ///
+ /// If there was a device error, just continue on and try again.
+ /// Other errors should be reported.
+ ///
+ if (Status != EFI_DEVICE_ERROR) {
+ return Status;
+ }
+ } else {
+ ///
+ /// If there was no error, the address was assigned and we must update our
+ /// records.
+ ///
+ Private->DeviceMapEntries++;
+ }
+
+ } while (Private->DeviceMapEntries < MAX_SMBUS_DEVICES);
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusFullArp() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do a directed Arp procress to assign the slave address of a single ARP-capable device.
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+ @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.
+
+ @retval EFI_OUT_OF_RESOURCES DeviceMapEntries is more than Max number of SMBus devices.
+ Or there is no available address to assign
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SmbusDirectedArp (
+ IN SMBUS_INSTANCE *Private,
+ IN EFI_SMBUS_UDID *SmbusUdid,
+ IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap;
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusDirectedArp() Start\n"));
+
+ if (Private->DeviceMapEntries >= MAX_SMBUS_DEVICES) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurrentDeviceMap = &Private->DeviceMap[Private->DeviceMapEntries];
+
+ ///
+ /// Find an available address to assign
+ ///
+ Status = GetNextAvailableAddress (
+ Private,
+ &CurrentDeviceMap->SmbusDeviceAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities = SmbusUdid->DeviceCapabilities;
+ CurrentDeviceMap->SmbusDeviceUdid.DeviceId = SmbusUdid->DeviceId;
+ CurrentDeviceMap->SmbusDeviceUdid.Interface = SmbusUdid->Interface;
+ CurrentDeviceMap->SmbusDeviceUdid.SubsystemDeviceId = SmbusUdid->SubsystemDeviceId;
+ CurrentDeviceMap->SmbusDeviceUdid.SubsystemVendorId = SmbusUdid->SubsystemVendorId;
+ CurrentDeviceMap->SmbusDeviceUdid.VendorId = SmbusUdid->VendorId;
+ CurrentDeviceMap->SmbusDeviceUdid.VendorRevision = SmbusUdid->VendorRevision;
+ CurrentDeviceMap->SmbusDeviceUdid.VendorSpecificId = SmbusUdid->VendorSpecificId;
+
+ Status = SmbusAssignAddress (Private, CurrentDeviceMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->DeviceMapEntries++;
+ SlaveAddress->SmbusDeviceAddress = CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress;
+
+ DEBUG ((EFI_D_INFO, "PEI SmbusDirectedArp() End\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find an available address to assign
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+ @param[in] SlaveAddress Buffer to store new Slave Address during directed ARP.
+
+ @retval EFI_OUT_OF_RESOURCES There is no available address to assign
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+GetNextAvailableAddress (
+ IN SMBUS_INSTANCE *Private,
+ IN EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress
+ )
+{
+ for (SlaveAddress->SmbusDeviceAddress = 0x03;
+ SlaveAddress->SmbusDeviceAddress < 0x7F;
+ SlaveAddress->SmbusDeviceAddress++
+ ) {
+ if (IsAddressAvailable (Private, *SlaveAddress)) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ Check whether the address is assignable.
+
+ @param[in] Private Pointer to the SMBUS_INSTANCE
+ @param[in] SlaveAddress The Slave Address for checking
+
+ @retval TRUE The address is assignable
+ @retval FALSE The address is not assignable
+**/
+BOOLEAN
+IsAddressAvailable (
+ IN SMBUS_INSTANCE *Private,
+ IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress
+ )
+{
+ UINT8 Index;
+
+ ///
+ /// See if we have already assigned this address to a device
+ ///
+ for (Index = 0; Index < Private->DeviceMapEntries; Index++) {
+ if (SlaveAddress.SmbusDeviceAddress == Private->DeviceMap[Index].SmbusDeviceAddress.SmbusDeviceAddress) {
+ return FALSE;
+ }
+ }
+ ///
+ /// See if this address is claimed by a platform non-ARP-capable device
+ ///
+ for (Index = 0; Index < Private->PlatformNumRsvd; Index++) {
+ if ((SlaveAddress.SmbusDeviceAddress << 1) == Private->PlatformRsvdAddr[Index]) {
+ return FALSE;
+ }
+ }
+ ///
+ /// See if this is a reserved address
+ ///
+ for (Index = 0; Index < SMBUS_NUM_RESERVED; Index++) {
+ if ((SlaveAddress.SmbusDeviceAddress << 1) == (UINTN) mReservedAddress[Index]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}