audk/Vlv2TbltDevicePkg/PlatformInitPei/Dimm.c

320 lines
8.4 KiB
C
Raw Normal View History

/** @file
Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
Module Name:
Dimm.c
Abstract:
PPI for reading SPD modules on DIMMs.
--*/
//
// Header Files
//
#include "Platformearlyinit.h"
#define DIMM_SOCKETS 4 // Total number of DIMM sockets allowed on
// the platform
#define DIMM_SEGMENTS 1 // Total number of Segments Per DIMM.
#define MEMORY_CHANNELS 2 // Total number of memory channels
// populated on the system board
//
// Prototypes
//
EFI_STATUS
EFIAPI
GetDimmState (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_DIMM_PPI *This,
IN UINT8 Dimm,
OUT PEI_PLATFORM_DIMM_STATE *State
);
EFI_STATUS
EFIAPI
SetDimmState (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_DIMM_PPI *This,
IN UINT8 Dimm,
IN PEI_PLATFORM_DIMM_STATE *State
);
EFI_STATUS
EFIAPI
ReadSpd (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_DIMM_PPI *This,
IN UINT8 Dimm,
IN UINT8 Offset,
IN UINTN Count,
IN OUT UINT8 *Buffer
);
static PEI_PLATFORM_DIMM_PPI mGchDimmPpi = {
DIMM_SOCKETS,
DIMM_SEGMENTS,
MEMORY_CHANNELS,
GetDimmState,
SetDimmState,
ReadSpd
};
static EFI_PEI_PPI_DESCRIPTOR mPpiPlatformDimm = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gPeiPlatformDimmPpiGuid,
&mGchDimmPpi
};
//
// Functions
//
/**
This function returns the current state of a single DIMM. Present indicates
that the DIMM slot is physically populated. Disabled indicates that the DIMM
should not be used.
@param PeiServices PEI services table pointer
@param This PPI pointer
@param Dimm DIMM to read from
@param State Pointer to a return buffer to be updated with the current state
of the DIMM
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
EFIAPI
GetDimmState (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_DIMM_PPI *This,
IN UINT8 Dimm,
OUT PEI_PLATFORM_DIMM_STATE *State
)
{
EFI_STATUS Status;
UINT8 Buffer;
PEI_ASSERT (PeiServices, (Dimm < This->DimmSockets));
//
// A failure here does not necessarily mean that no DIMM is present.
// Read a single byte. All we care about is the return status.
//
Status = ReadSpd (
PeiServices,
This,
Dimm,
0,
1,
&Buffer
);
if (EFI_ERROR (Status)) {
State->Present = 0;
} else {
State->Present = 1;
}
//
// BUGBUG: Update to check platform variable when it is available
//
State->Disabled = 0;
State->Reserved = 0;
return EFI_SUCCESS;
}
/**
This function updates the state of a single DIMM.
@param PeiServices PEI services table pointer
@param This PPI pointer
@param Dimm DIMM to set state for
@param State Pointer to the state information to set.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_UNSUPPORTED The function is not supported.
**/
EFI_STATUS
EFIAPI
SetDimmState (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_DIMM_PPI *This,
IN UINT8 Dimm,
IN PEI_PLATFORM_DIMM_STATE *State
)
{
return EFI_UNSUPPORTED;
}
/**
This function reads SPD information from a DIMM.
PeiServices PEI services table pointer
This PPI pointer
Dimm DIMM to read from
Offset Offset in DIMM
Count Number of bytes
Buffer Return buffer
@param EFI_SUCCESS The function completed successfully.
@param EFI_DEVICE_ERROR The DIMM being accessed reported a device error,
does not have an SPD module, or is not installed in
the system.
@retval EFI_TIMEOUT Time out trying to read the SPD module.
@retval EFI_INVALID_PARAMETER A parameter was outside the legal limits.
**/
EFI_STATUS
EFIAPI
ReadSpd (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_DIMM_PPI *This,
IN UINT8 Dimm,
IN UINT8 Offset,
IN UINTN Count,
IN OUT UINT8 *Buffer
)
{
EFI_STATUS Status;
PEI_SMBUS_PPI *Smbus;
UINTN Index;
UINTN Index1;
EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
EFI_SMBUS_DEVICE_COMMAND Command;
UINTN Length;
Status = (**PeiServices).LocatePpi (
PeiServices,
&gPeiSmbusPpiGuid, // GUID
0, // INSTANCE
NULL, // EFI_PEI_PPI_DESCRIPTOR
&Smbus // PPI
);
ASSERT_PEI_ERROR (PeiServices, Status);
switch (Dimm) {
case 0:
SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_A_1 >> 1;
break;
case 1:
SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_A_2 >> 1;
break;
case 2:
SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_B_1 >> 1;
break;
case 3:
SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_B_2 >> 1;
break;
default:
return EFI_INVALID_PARAMETER;
}
Index = Count % 4;
if (Index != 0) {
//
// read the first serveral bytes to speed up following reading
//
for (Index1 = 0; Index1 < Index; Index1++) {
Length = 1;
Command = Offset + Index1;
Status = Smbus->Execute (
PeiServices,
Smbus,
SlaveAddress,
Command,
EfiSmbusReadByte,
FALSE,
&Length,
&Buffer[Index1]
);
if (EFI_ERROR(Status)) {
return Status;
}
}
}
//
// Now collect all the remaining bytes on 4 bytes block
//
for (; Index < Count; Index += 2) {
Command = Index + Offset;
Length = 2;
Status = Smbus->Execute (
PeiServices,
Smbus,
SlaveAddress,
Command,
EfiSmbusReadWord,
FALSE,
&Length,
&Buffer[Index]
);
if (EFI_ERROR(Status)) {
return Status;
}
Index += 2;
Command = Index + Offset;
Length = 2;
Status = Smbus->Execute (
PeiServices,
Smbus,
SlaveAddress,
Command,
EfiSmbusReadWord,
FALSE,
&Length,
&Buffer[Index]
);
if (EFI_ERROR(Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
This function initializes the PEIM. It simply installs the DIMM PPI.
@param FfsHeader Not used by this function
@param PeiServices Pointer to PEI services table
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
EFIAPI
PeimInitializeDimm (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *SmbusPpi
)
{
EFI_STATUS Status;
Status = (**PeiServices).InstallPpi (
PeiServices,
&mPpiPlatformDimm
);
ASSERT_PEI_ERROR (PeiServices, Status);
return EFI_SUCCESS;
}