]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/Library/MultiPlatformLib/BoardClkGens/BoardClkGens.c
99d750a2a875df07fd2acb6173abecaa6533b5c5
[mirror_edk2.git] / Vlv2TbltDevicePkg / Library / MultiPlatformLib / BoardClkGens / BoardClkGens.c
1 /** @file
2 Clock generator setting for multiplatform.
3
4 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials are licensed and made available under
7 the terms and conditions of the BSD License that accompanies this distribution.
8 The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14
15 **/
16
17 #include <BoardClkGens.h>
18 #include <Guid/SetupVariable.h>
19 #include <Ppi/ReadOnlyVariable2.h>
20 #include <Library/BaseMemoryLib.h>
21
22 #ifndef __GNUC__
23 #pragma optimize( "", off )
24 #endif
25
26 #define CLKGEN_EN 1
27 #define EFI_DEBUG 1
28
29 CLOCK_GENERATOR_DETAILS mSupportedClockGeneratorTable[] =
30 {
31 { ClockGeneratorCk410, CK410_GENERATOR_ID , CK410_GENERATOR_SPREAD_SPECTRUM_BYTE, CK410_GENERATOR_SPREAD_SPECTRUM_BIT },
32 { ClockGeneratorCk505, CK505_GENERATOR_ID , CK505_GENERATOR_SPREAD_SPECTRUM_BYTE, CK505_GENERATOR_SPREAD_SPECTRUM_BIT }
33 };
34
35 /**
36 Configure the clock generator using the SMBUS PPI services.
37
38 This function performs a block write, and dumps debug information.
39
40 @param PeiServices General purpose services available to every PEIM.
41 @param ClockType Clock generator's model name.
42 @param ClockAddress SMBUS address of clock generator.
43 @param ConfigurationTableLength Length of configuration table.
44 @param ConfigurationTable Pointer of configuration table.
45
46 @retval EFI_SUCCESS - Operation success.
47
48 **/
49 EFI_STATUS
50 ConfigureClockGenerator (
51 IN EFI_PEI_SERVICES **PeiServices,
52 IN EFI_PEI_SMBUS_PPI *SmbusPpi,
53 IN CLOCK_GENERATOR_TYPE ClockType,
54 IN UINT8 ClockAddress,
55 IN UINTN ConfigurationTableLength,
56 IN OUT UINT8 *ConfigurationTable
57 )
58 {
59
60 EFI_STATUS Status;
61 EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
62 UINT8 Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
63 UINTN Length;
64 EFI_SMBUS_DEVICE_COMMAND Command;
65 #if CLKGEN_CONFIG_EXTRA
66 UINT8 j;
67 #endif
68
69 //
70 // Verify input arguments
71 //
72 ASSERT (ConfigurationTableLength >= 6);
73 ASSERT (ConfigurationTableLength <= MAX_CLOCK_GENERATOR_BUFFER_LENGTH);
74 ASSERT (ClockType < ClockGeneratorMax);
75 ASSERT (ConfigurationTable != NULL);
76
77 //
78 // Read the clock generator
79 //
80 SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
81 Length = sizeof (Buffer);
82 Command = 0;
83 Status = SmbusPpi->Execute (
84 PeiServices,
85 SmbusPpi,
86 SlaveAddress,
87 Command,
88 EfiSmbusReadBlock,
89 FALSE,
90 &Length,
91 Buffer
92 );
93 ASSERT_EFI_ERROR (Status);
94
95 #ifdef EFI_DEBUG
96 {
97 UINT8 i;
98 for (i = 0; i < sizeof (Buffer); i++) {
99 DEBUG((EFI_D_ERROR, "CK505 default Clock Generator Byte %d: %x\n", i, Buffer[i]));
100 }
101 #if CLKGEN_EN
102 for (i = 0; i < ConfigurationTableLength; i++) {
103 DEBUG((EFI_D_ERROR, "BIOS structure Clock Generator Byte %d: %x\n", i, ConfigurationTable[i]));
104 }
105 #endif
106 }
107 #endif
108
109 DEBUG((EFI_D_ERROR, "Expected Clock Generator ID is %x, expecting %x\n", mSupportedClockGeneratorTable[ClockType].ClockId,(Buffer[7]&0xF)));
110
111 //
112 // Program clock generator
113 //
114 Command = 0;
115 #if CLKGEN_EN
116 #if CLKGEN_CONFIG_EXTRA
117 for (j = 0; j < ConfigurationTableLength; j++) {
118 Buffer[j] = ConfigurationTable[j];
119 }
120
121 Buffer[30] = 0x00;
122
123 Status = SmbusPpi->Execute (
124 PeiServices,
125 SmbusPpi,
126 SlaveAddress,
127 Command,
128 EfiSmbusWriteBlock,
129 FALSE,
130 &Length,
131 Buffer
132 );
133 #else
134 Status = SmbusPpi->Execute (
135 PeiServices,
136 SmbusPpi,
137 SlaveAddress,
138 Command,
139 EfiSmbusWriteBlock,
140 FALSE,
141 &ConfigurationTableLength,
142 ConfigurationTable
143 );
144 #endif // CLKGEN_CONFIG_EXTRA
145 #else
146 ConfigurationTable[4] = (ConfigurationTable[4] & 0x3) | (Buffer[4] & 0xFC);
147 Command = 4;
148 Length = 1;
149 Status = SmbusPpi->Execute (
150 PeiServices,
151 SmbusPpi,
152 SlaveAddress,
153 Command,
154 EfiSmbusWriteBlock,
155 FALSE,
156 &Length,
157 &ConfigurationTable[4]
158 );
159 #endif //CLKGEN_EN
160 ASSERT_EFI_ERROR (Status);
161
162 //
163 // Dump contents after write
164 //
165 #ifdef EFI_DEBUG
166 {
167 UINT8 i;
168 SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
169 Length = sizeof (Buffer);
170 Command = 0;
171 Status = SmbusPpi->Execute (
172 PeiServices,
173 SmbusPpi,
174 SlaveAddress,
175 Command,
176 EfiSmbusReadBlock,
177 FALSE,
178 &Length,
179 Buffer
180 );
181
182 for (i = 0; i < ConfigurationTableLength; i++) {
183 DEBUG((EFI_D_ERROR, "Clock Generator Byte %d: %x\n", i, Buffer[i]));
184 }
185 }
186 #endif
187
188 return EFI_SUCCESS;
189 }
190
191 /**
192 Configure the clock generator using the SMBUS PPI services.
193
194 This function performs a block write, and dumps debug information.
195
196 @param PeiServices General purpose services available to every PEIM.
197 @param ClockType Clock generator's model name.
198 @param ClockAddress SMBUS address of clock generator.
199 @param ConfigurationTableLength Length of configuration table.
200 @param ConfigurationTable Pointer of configuration table.
201
202
203 @retval EFI_SUCCESS Operation success.
204
205 **/
206 UINT8
207 ReadClockGeneratorID (
208 IN EFI_PEI_SERVICES **PeiServices,
209 IN EFI_PEI_SMBUS_PPI *SmbusPpi,
210 IN UINT8 ClockAddress
211 )
212 {
213 EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
214 UINT8 Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
215 UINTN Length;
216 EFI_SMBUS_DEVICE_COMMAND Command;
217
218 //
219 // Read the clock generator
220 //
221 SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
222 Length = sizeof (Buffer);
223 Command = 0;
224 SmbusPpi->Execute (
225 PeiServices,
226 SmbusPpi,
227 SlaveAddress,
228 Command,
229 EfiSmbusReadBlock,
230 FALSE,
231 &Length,
232 Buffer
233 );
234
235 //
236 // Sanity check that the requested clock type is present in our supported clocks table
237 //
238 DEBUG((EFI_D_ERROR, "Expected Clock Generator ID is 0x%x\n", Buffer[7]));
239
240 return (Buffer[7]);
241 }
242
243 /**
244 Configure the clock generator to enable free-running operation. This keeps
245 the clocks from being stopped when the system enters C3 or C4.
246
247 @param None
248
249 @retval EFI_SUCCESS The function completed successfully.
250
251 **/
252 EFI_STATUS
253 ConfigurePlatformClocks (
254 IN EFI_PEI_SERVICES **PeiServices,
255 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
256 IN VOID *SmbusPpi
257 )
258 {
259 //
260 // Comment it out for now
261 // Not supported by Hybrid model.
262 //
263 EFI_STATUS Status;
264 UINT8 *ConfigurationTable;
265
266 CLOCK_GENERATOR_TYPE ClockType = ClockGeneratorCk505;
267 UINT8 ConfigurationTable_Desktop[] = CLOCK_GENERATOR_SETTINGS_DESKTOP;
268 UINT8 ConfigurationTable_Mobile[] = CLOCK_GENERATOR_SETTINGS_MOBILE;
269 UINT8 ConfigurationTable_Tablet[] = CLOCK_GENERATOR_SEETINGS_TABLET;
270
271 EFI_PLATFORM_INFO_HOB *PlatformInfoHob;
272 BOOLEAN EnableSpreadSpectrum;
273 SYSTEM_CONFIGURATION SystemConfiguration;
274
275 UINTN Length;
276 EFI_SMBUS_DEVICE_COMMAND Command;
277 EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
278 UINT8 Data;
279
280 UINT8 ClockAddress = CLOCK_GENERATOR_ADDRESS;
281 UINTN VariableSize;
282 EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
283
284 //
285 // Obtain Platform Info from HOB.
286 //
287 Status = GetPlatformInfoHob ((CONST EFI_PEI_SERVICES **) PeiServices, &PlatformInfoHob);
288 ASSERT_EFI_ERROR (Status);
289
290 DEBUG((EFI_D_ERROR, "PlatformInfo protocol is working in ConfigurePlatformClocks()...%x\n",PlatformInfoHob->PlatformFlavor));
291
292 //
293 // Locate SMBUS PPI
294 //
295 Status = (**PeiServices).LocatePpi (
296 (CONST EFI_PEI_SERVICES **) PeiServices,
297 &gEfiPeiSmbusPpiGuid,
298 0,
299 NULL,
300 &SmbusPpi
301 );
302 ASSERT_EFI_ERROR (Status);
303
304 Data = 0;
305 SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
306 Length = 1;
307 Command = 0x87; //Control Register 7 Vendor ID Check
308 Status = ((EFI_PEI_SMBUS_PPI *) SmbusPpi)->Execute (
309 PeiServices,
310 SmbusPpi,
311 SlaveAddress,
312 Command,
313 EfiSmbusReadByte,
314 FALSE,
315 &Length,
316 &Data
317 );
318
319 if (EFI_ERROR (Status) || ((Data & 0x0F) != CK505_GENERATOR_ID)) {
320 DEBUG((EFI_D_ERROR, "Clock Generator CK505 Not Present, vendor ID on board is %x\n",(Data & 0x0F)));
321 return EFI_SUCCESS;
322 }
323
324 EnableSpreadSpectrum = FALSE;
325 VariableSize = sizeof (SYSTEM_CONFIGURATION);
326 ZeroMem (&SystemConfiguration, sizeof (SYSTEM_CONFIGURATION));
327
328 Status = (*PeiServices)->LocatePpi (
329 (CONST EFI_PEI_SERVICES **) PeiServices,
330 &gEfiPeiReadOnlyVariable2PpiGuid,
331 0,
332 NULL,
333 (VOID **) &Variable
334 );
335 //
336 // Use normal setup default from NVRAM variable,
337 // the Platform Mode (manufacturing/safe/normal) is handle in PeiGetVariable.
338 //
339 VariableSize = sizeof(SYSTEM_CONFIGURATION);
340 Status = Variable->GetVariable (Variable,
341 L"Setup",
342 &gEfiSetupVariableGuid,
343 NULL,
344 &VariableSize,
345 &SystemConfiguration);
346 if (EFI_ERROR (Status) || VariableSize != sizeof(SYSTEM_CONFIGURATION)) {
347 //The setup variable is corrupted
348 VariableSize = sizeof(SYSTEM_CONFIGURATION);
349 Status = Variable->GetVariable(Variable,
350 L"SetupRecovery",
351 &gEfiSetupVariableGuid,
352 NULL,
353 &VariableSize,
354 &SystemConfiguration
355 );
356 ASSERT_EFI_ERROR (Status);
357 }
358 if(!EFI_ERROR (Status)){
359 EnableSpreadSpectrum = SystemConfiguration.EnableClockSpreadSpec;
360 }
361
362 //
363 // Perform platform-specific intialization dependent upon Board ID:
364 //
365 DEBUG((EFI_D_ERROR, "board id is %x, platform id is %x\n",PlatformInfoHob->BoardId,PlatformInfoHob->PlatformFlavor));
366
367
368 switch (PlatformInfoHob->BoardId) {
369 case BOARD_ID_MINNOW2:
370 case BOARD_ID_MINNOW2_TURBOT:
371 default:
372 switch(PlatformInfoHob->PlatformFlavor) {
373 case FlavorTablet:
374 ConfigurationTable = ConfigurationTable_Tablet;
375 Length = sizeof (ConfigurationTable_Tablet);
376 break;
377 case FlavorMobile:
378 ConfigurationTable = ConfigurationTable_Mobile;
379 Length = sizeof (ConfigurationTable_Mobile);
380 break;
381 case FlavorDesktop:
382 default:
383 ConfigurationTable = ConfigurationTable_Desktop;
384 Length = sizeof (ConfigurationTable_Desktop);
385 break;
386 }
387 break;
388 }
389
390 //
391 // Perform common clock initialization:
392 //
393 // Program Spread Spectrum function.
394 //
395 if (EnableSpreadSpectrum)
396 {
397 ConfigurationTable[mSupportedClockGeneratorTable[ClockType].SpreadSpectrumByteOffset] |= mSupportedClockGeneratorTable[ClockType].SpreadSpectrumBitOffset;
398 } else {
399 ConfigurationTable[mSupportedClockGeneratorTable[ClockType].SpreadSpectrumByteOffset] &= ~(mSupportedClockGeneratorTable[ClockType].SpreadSpectrumBitOffset);
400 }
401
402
403 #if CLKGEN_EN
404 Status = ConfigureClockGenerator (PeiServices, SmbusPpi, ClockType, ClockAddress, Length, ConfigurationTable);
405 ASSERT_EFI_ERROR (Status);
406 #endif // CLKGEN_EN
407 return EFI_SUCCESS;
408 }
409
410 static EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
411 {
412 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
413 &gEfiPeiSmbusPpiGuid,
414 ConfigurePlatformClocks
415 }
416 };
417
418 EFI_STATUS
419 InstallPlatformClocksNotify (
420 IN CONST EFI_PEI_SERVICES **PeiServices
421 )
422 {
423 EFI_STATUS Status;
424
425 DEBUG ((EFI_D_INFO, "InstallPlatformClocksNotify()...\n"));
426
427 Status = (*PeiServices)->NotifyPpi(PeiServices, &mNotifyList[0]);
428 ASSERT_EFI_ERROR (Status);
429 return EFI_SUCCESS;
430
431 }
432
433 #ifndef __GNUC__
434 #pragma optimize( "", on )
435 #endif