1/** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 6 This program and the accompanying materials are licensed and made available under 7 8 the terms and conditions of the BSD License that accompanies this distribution. 9 10 The full text of the license may be found at 11 12 http://opensource.org/licenses/bsd-license.php. 13 14 15 16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 20 21 22 23Module Name: 24 25 26 Dimm.c 27 28Abstract: 29 30 PPI for reading SPD modules on DIMMs. 31 32--*/ 33 34 35// 36// Header Files 37// 38#include "Platformearlyinit.h" 39 40#define DIMM_SOCKETS 4 // Total number of DIMM sockets allowed on 41 // the platform 42#define DIMM_SEGMENTS 1 // Total number of Segments Per DIMM. 43#define MEMORY_CHANNELS 2 // Total number of memory channels 44 // populated on the system board 45// 46// Prototypes 47// 48 49EFI_STATUS 50EFIAPI 51GetDimmState ( 52 IN EFI_PEI_SERVICES **PeiServices, 53 IN PEI_PLATFORM_DIMM_PPI *This, 54 IN UINT8 Dimm, 55 OUT PEI_PLATFORM_DIMM_STATE *State 56 ); 57 58EFI_STATUS 59EFIAPI 60SetDimmState ( 61 IN EFI_PEI_SERVICES **PeiServices, 62 IN PEI_PLATFORM_DIMM_PPI *This, 63 IN UINT8 Dimm, 64 IN PEI_PLATFORM_DIMM_STATE *State 65 ); 66 67EFI_STATUS 68EFIAPI 69ReadSpd ( 70 IN EFI_PEI_SERVICES **PeiServices, 71 IN PEI_PLATFORM_DIMM_PPI *This, 72 IN UINT8 Dimm, 73 IN UINT8 Offset, 74 IN UINTN Count, 75 IN OUT UINT8 *Buffer 76 ); 77 78static PEI_PLATFORM_DIMM_PPI mGchDimmPpi = { 79 DIMM_SOCKETS, 80 DIMM_SEGMENTS, 81 MEMORY_CHANNELS, 82 GetDimmState, 83 SetDimmState, 84 ReadSpd 85}; 86 87static EFI_PEI_PPI_DESCRIPTOR mPpiPlatformDimm = { 88 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 89 &gPeiPlatformDimmPpiGuid, 90 &mGchDimmPpi 91}; 92 93 94// 95// Functions 96// 97 98/** 99 This function returns the current state of a single DIMM. Present indicates 100 that the DIMM slot is physically populated. Disabled indicates that the DIMM 101 should not be used. 102 103 @param PeiServices PEI services table pointer 104 @param This PPI pointer 105 @param Dimm DIMM to read from 106 @param State Pointer to a return buffer to be updated with the current state 107 of the DIMM 108 109 @retval EFI_SUCCESS The function completed successfully. 110 111**/ 112EFI_STATUS 113EFIAPI 114GetDimmState ( 115 IN EFI_PEI_SERVICES **PeiServices, 116 IN PEI_PLATFORM_DIMM_PPI *This, 117 IN UINT8 Dimm, 118 OUT PEI_PLATFORM_DIMM_STATE *State 119 ) 120{ 121 EFI_STATUS Status; 122 UINT8 Buffer; 123 124 PEI_ASSERT (PeiServices, (Dimm < This->DimmSockets)); 125 126 // 127 // A failure here does not necessarily mean that no DIMM is present. 128 // Read a single byte. All we care about is the return status. 129 // 130 Status = ReadSpd ( 131 PeiServices, 132 This, 133 Dimm, 134 0, 135 1, 136 &Buffer 137 ); 138 139 if (EFI_ERROR (Status)) { 140 State->Present = 0; 141 } else { 142 State->Present = 1; 143 } 144 145 // 146 // BUGBUG: Update to check platform variable when it is available 147 // 148 State->Disabled = 0; 149 State->Reserved = 0; 150 151 return EFI_SUCCESS; 152} 153 154/** 155 156 This function updates the state of a single DIMM. 157 158 @param PeiServices PEI services table pointer 159 @param This PPI pointer 160 @param Dimm DIMM to set state for 161 @param State Pointer to the state information to set. 162 163 @retval EFI_SUCCESS The function completed successfully. 164 @retval EFI_UNSUPPORTED The function is not supported. 165 166**/ 167EFI_STATUS 168EFIAPI 169SetDimmState ( 170 IN EFI_PEI_SERVICES **PeiServices, 171 IN PEI_PLATFORM_DIMM_PPI *This, 172 IN UINT8 Dimm, 173 IN PEI_PLATFORM_DIMM_STATE *State 174 ) 175{ 176 return EFI_UNSUPPORTED; 177} 178 179/** 180 This function reads SPD information from a DIMM. 181 182 PeiServices PEI services table pointer 183 This PPI pointer 184 Dimm DIMM to read from 185 Offset Offset in DIMM 186 Count Number of bytes 187 Buffer Return buffer 188 189 @param EFI_SUCCESS The function completed successfully. 190 @param EFI_DEVICE_ERROR The DIMM being accessed reported a device error, 191 does not have an SPD module, or is not installed in 192 the system. 193 @retval EFI_TIMEOUT Time out trying to read the SPD module. 194 @retval EFI_INVALID_PARAMETER A parameter was outside the legal limits. 195 196**/ 197EFI_STATUS 198EFIAPI 199ReadSpd ( 200 IN EFI_PEI_SERVICES **PeiServices, 201 IN PEI_PLATFORM_DIMM_PPI *This, 202 IN UINT8 Dimm, 203 IN UINT8 Offset, 204 IN UINTN Count, 205 IN OUT UINT8 *Buffer 206 ) 207{ 208 EFI_STATUS Status; 209 PEI_SMBUS_PPI *Smbus; 210 UINTN Index; 211 UINTN Index1; 212 EFI_SMBUS_DEVICE_ADDRESS SlaveAddress; 213 EFI_SMBUS_DEVICE_COMMAND Command; 214 UINTN Length; 215 216 Status = (**PeiServices).LocatePpi ( 217 PeiServices, 218 &gPeiSmbusPpiGuid, // GUID 219 0, // INSTANCE 220 NULL, // EFI_PEI_PPI_DESCRIPTOR 221 &Smbus // PPI 222 ); 223 ASSERT_PEI_ERROR (PeiServices, Status); 224 225 switch (Dimm) { 226 case 0: 227 SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_A_1 >> 1; 228 break; 229 case 1: 230 SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_A_2 >> 1; 231 break; 232 case 2: 233 SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_B_1 >> 1; 234 break; 235 case 3: 236 SlaveAddress.SmbusDeviceAddress = SMBUS_ADDR_CH_B_2 >> 1; 237 break; 238 default: 239 return EFI_INVALID_PARAMETER; 240 } 241 242 Index = Count % 4; 243 if (Index != 0) { 244 // 245 // read the first serveral bytes to speed up following reading 246 // 247 for (Index1 = 0; Index1 < Index; Index1++) { 248 Length = 1; 249 Command = Offset + Index1; 250 Status = Smbus->Execute ( 251 PeiServices, 252 Smbus, 253 SlaveAddress, 254 Command, 255 EfiSmbusReadByte, 256 FALSE, 257 &Length, 258 &Buffer[Index1] 259 ); 260 if (EFI_ERROR(Status)) { 261 return Status; 262 } 263 } 264 } 265 266 // 267 // Now collect all the remaining bytes on 4 bytes block 268 // 269 for (; Index < Count; Index += 2) { 270 Command = Index + Offset; 271 Length = 2; 272 Status = Smbus->Execute ( 273 PeiServices, 274 Smbus, 275 SlaveAddress, 276 Command, 277 EfiSmbusReadWord, 278 FALSE, 279 &Length, 280 &Buffer[Index] 281 ); 282 if (EFI_ERROR(Status)) { 283 return Status; 284 } 285 286 Index += 2; 287 Command = Index + Offset; 288 Length = 2; 289 Status = Smbus->Execute ( 290 PeiServices, 291 Smbus, 292 SlaveAddress, 293 Command, 294 EfiSmbusReadWord, 295 FALSE, 296 &Length, 297 &Buffer[Index] 298 ); 299 if (EFI_ERROR(Status)) { 300 return Status; 301 } 302 } 303 return EFI_SUCCESS; 304} 305 306/** 307 This function initializes the PEIM. It simply installs the DIMM PPI. 308 309 @param FfsHeader Not used by this function 310 @param PeiServices Pointer to PEI services table 311 312 @retval EFI_SUCCESS The function completed successfully. 313 314**/ 315EFI_STATUS 316EFIAPI 317PeimInitializeDimm ( 318 IN EFI_PEI_SERVICES **PeiServices, 319 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, 320 IN VOID *SmbusPpi 321 ) 322{ 323 EFI_STATUS Status; 324 325 Status = (**PeiServices).InstallPpi ( 326 PeiServices, 327 &mPpiPlatformDimm 328 ); 329 ASSERT_PEI_ERROR (PeiServices, Status); 330 331 return EFI_SUCCESS; 332} 333 334