• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 Module Name:
24 
25 
26   Dimm.c
27 
28 Abstract:
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 
49 EFI_STATUS
50 EFIAPI
51 GetDimmState (
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 
58 EFI_STATUS
59 EFIAPI
60 SetDimmState (
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 
67 EFI_STATUS
68 EFIAPI
69 ReadSpd (
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 
78 static PEI_PLATFORM_DIMM_PPI mGchDimmPpi = {
79   DIMM_SOCKETS,
80   DIMM_SEGMENTS,
81   MEMORY_CHANNELS,
82   GetDimmState,
83   SetDimmState,
84   ReadSpd
85 };
86 
87 static 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
GetDimmState(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_PLATFORM_DIMM_PPI * This,IN UINT8 Dimm,OUT PEI_PLATFORM_DIMM_STATE * State)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 **/
112 EFI_STATUS
113 EFIAPI
114 GetDimmState (
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
SetDimmState(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_PLATFORM_DIMM_PPI * This,IN UINT8 Dimm,IN PEI_PLATFORM_DIMM_STATE * State)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 **/
167 EFI_STATUS
168 EFIAPI
169 SetDimmState (
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.
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)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 **/
197 EFI_STATUS
198 EFIAPI
199 ReadSpd (
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.
PeimInitializeDimm(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * SmbusPpi)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 **/
315 EFI_STATUS
316 EFIAPI
317 PeimInitializeDimm (
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