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