blob: dbfdce877efaf7c7084e2ae7dfd6cbc779d3161f [file] [log] [blame]
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * AMD Library
6 *
7 * Contains interface to the AMD AGESA library
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: Lib
efdesign9884cbce22011-08-04 12:09:17 -060012 * @e \$Revision: 44325 $ @e \$Date: 2010-12-22 03:29:53 -0700 (Wed, 22 Dec 2010) $
Frank Vibrans2b4c8312011-02-14 18:30:54 +000013 *
14 */
15/*
16 *****************************************************************************
17 *
18 * Copyright (c) 2011, Advanced Micro Devices, Inc.
19 * All rights reserved.
efdesign9805a89ab2011-06-20 17:38:49 -070020 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000021 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
efdesign9805a89ab2011-06-20 17:38:49 -070028 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
Frank Vibrans2b4c8312011-02-14 18:30:54 +000030 * from this software without specific prior written permission.
efdesign9805a89ab2011-06-20 17:38:49 -070031 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000032 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
efdesign9805a89ab2011-06-20 17:38:49 -070042 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000043 * ***************************************************************************
44 *
45 */
46
47
48/*----------------------------------------------------------------------------------------
49 * M O D U L E S U S E D
50 *----------------------------------------------------------------------------------------
51 */
52
53#include "AGESA.h"
54#include "Ids.h"
55#include "cpuRegisters.h"
56#include "amdlib.h"
57#include "Filecode.h"
58CODE_GROUP (G1_PEICC)
59RDATA_GROUP (G1_PEICC)
60
61#define FILECODE LIB_AMDLIB_FILECODE
62
63/*----------------------------------------------------------------------------------------
64 * D E F I N I T I O N S A N D M A C R O S
65 *----------------------------------------------------------------------------------------
66 */
67
68
69/*----------------------------------------------------------------------------------------
70 * T Y P E D E F S A N D S T R U C T U R E S
71 *----------------------------------------------------------------------------------------
72 */
73
74
75/*----------------------------------------------------------------------------------------
76 * P R O T O T Y P E S O F L O C A L F U N C T I O N S
77 *----------------------------------------------------------------------------------------
78 */
79
80
81BOOLEAN
82STATIC
83GetPciMmioAddress (
84 OUT UINT64 *MmioAddress,
85 OUT UINT32 *MmioSize,
86 IN AMD_CONFIG_PARAMS *StdHeader
87 );
88
89VOID
90STATIC
91LibAmdGetDataFromPtr (
92 IN ACCESS_WIDTH AccessWidth,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +110093 IN CONST VOID *Data,
94 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +000095 OUT UINT32 *TemData,
96 OUT UINT32 *TempDataMask
97 );
98
99/*----------------------------------------------------------------------------------------
100 * E X P O R T E D F U N C T I O N S
101 *----------------------------------------------------------------------------------------
102 */
103UINT8
104ReadIo8 (
105 IN UINT16 Address
106 )
107{
108 return __inbyte (Address);
109}
110UINT16
111ReadIo16 (
112 IN UINT16 Address
113 )
114{
115 return __inword (Address);
116}
117UINT32
118ReadIo32 (
119 IN UINT16 Address
120 )
121{
122 return __indword (Address);
123}
124VOID
125WriteIo8 (
126 IN UINT16 Address,
127 IN UINT8 Data
128 )
129{
130 __outbyte (Address, Data);
131}
132VOID
133WriteIo16 (
134 IN UINT16 Address,
135 IN UINT16 Data
136 )
137{
138 __outword (Address, Data);
139}
140VOID
141WriteIo32 (
142 IN UINT16 Address,
143 IN UINT32 Data
144 )
145{
146 __outdword (Address, Data);
147}
efdesign9805a89ab2011-06-20 17:38:49 -0700148STATIC
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000149UINT64 SetFsBase (
150 UINT64 address
151 )
152{
153 UINT64 hwcr;
154 hwcr = __readmsr (0xC0010015);
155 __writemsr (0xC0010015, hwcr | 1 << 17);
156 __writemsr (0xC0000100, address);
157 return hwcr;
158}
efdesign9805a89ab2011-06-20 17:38:49 -0700159STATIC
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000160VOID
161RestoreHwcr (
efdesign9805a89ab2011-06-20 17:38:49 -0700162 UINT64
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000163 value
164 )
165{
166 __writemsr (0xC0010015, value);
167}
168UINT8
169Read64Mem8 (
170 IN UINT64 Address
171 )
172{
173 UINT8 dataRead;
174 UINT64 hwcrSave;
175 if ((Address >> 32) == 0) {
176 return *(volatile UINT8 *) (UINTN) Address;
177 }
178 hwcrSave = SetFsBase (Address);
179 dataRead = __readfsbyte (0);
180 RestoreHwcr (hwcrSave);
181 return dataRead;
182}
183UINT16
184Read64Mem16 (
185 IN UINT64 Address
186 )
187{
188 UINT16 dataRead;
189 UINT64 hwcrSave;
190 if ((Address >> 32) == 0) {
191 return *(volatile UINT16 *) (UINTN) Address;
192 }
193 hwcrSave = SetFsBase (Address);
194 dataRead = __readfsword (0);
195 RestoreHwcr (hwcrSave);
196 return dataRead;
197}
198UINT32
199Read64Mem32 (
200 IN UINT64 Address
201 )
202{
203 UINT32 dataRead;
204 UINT64 hwcrSave;
205 if ((Address >> 32) == 0) {
206 return *(volatile UINT32 *) (UINTN) Address;
207 }
208 hwcrSave = SetFsBase (Address);
209 dataRead = __readfsdword (0);
210 RestoreHwcr (hwcrSave);
211 return dataRead;
212 }
213VOID
214Write64Mem8 (
215 IN UINT64 Address,
216 IN UINT8 Data
217 )
218{
219 if ((Address >> 32) == 0){
220 *(volatile UINT8 *) (UINTN) Address = Data;
efdesign9805a89ab2011-06-20 17:38:49 -0700221 }
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000222 else {
223 UINT64 hwcrSave;
224 hwcrSave = SetFsBase (Address);
225 __writefsbyte (0, Data);
226 RestoreHwcr (hwcrSave);
227 }
228}
229VOID
230Write64Mem16 (
231 IN UINT64 Address,
232 IN UINT16 Data
233 )
234{
235 if ((Address >> 32) == 0){
236 *(volatile UINT16 *) (UINTN) Address = Data;
efdesign9805a89ab2011-06-20 17:38:49 -0700237 }
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000238 else {
239 UINT64 hwcrSave;
240 hwcrSave = SetFsBase (Address);
241 __writefsword (0, Data);
242 RestoreHwcr (hwcrSave);
243 }
244}
245VOID
246Write64Mem32 (
247 IN UINT64 Address,
248 IN UINT32 Data
249 )
250{
251 if ((Address >> 32) == 0){
252 *(volatile UINT32 *) (UINTN) Address = Data;
efdesign9805a89ab2011-06-20 17:38:49 -0700253 }
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000254 else {
255 UINT64 hwcrSave;
256 hwcrSave = SetFsBase (Address);
257 __writefsdword (0, Data);
258 RestoreHwcr (hwcrSave);
259 }
260}
261VOID
262LibAmdReadCpuReg (
263 IN UINT8 RegNum,
264 OUT UINT32 *Value
265 )
266{
267 *Value = 0;
268 switch (RegNum){
269 case CR4_REG:
270 *Value = __readcr4 ();
271 break;
272 case DR0_REG:
273 *Value = __readdr (0);
274 break;
275 case DR1_REG:
276 *Value = __readdr (1);
277 break;
278 case DR2_REG:
279 *Value = __readdr (2);
280 break;
281 case DR3_REG:
282 *Value = __readdr (3);
283 break;
284 case DR7_REG:
285 *Value = __readdr (7);
286 break;
287 default:
288 *Value = -1;
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300289 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000290 }
291}
292VOID
293LibAmdWriteCpuReg (
294 IN UINT8 RegNum,
295 IN UINT32 Value
296 )
297{
298 switch (RegNum){
299 case CR4_REG:
300 __writecr4 (Value);
301 break;
302 case DR0_REG:
303 __writedr (0, Value);
304 break;
305 case DR1_REG:
306 __writedr (1, Value);
307 break;
308 case DR2_REG:
309 __writedr (2, Value);
310 break;
311 case DR3_REG:
312 __writedr (3, Value);
313 break;
314 case DR7_REG:
315 __writedr (7, Value);
316 break;
317 default:
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300318 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000319 }
320}
321VOID
322LibAmdWriteBackInvalidateCache (
323 IN VOID
324 )
325{
326 __wbinvd ();
327}
328VOID
329LibAmdHDTBreakPoint (
330 VOID
331 )
332{
333 __writemsr (0xC001100A, __readmsr (0xC001100A) | 1);
efdesign9805a89ab2011-06-20 17:38:49 -0700334 __debugbreak (); // do you really need icebp? If so, go back to asm code
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000335}
336UINT8
337LibAmdBitScanForward (
338 IN UINT32 value
339 )
340{
341 UINTN Index;
342 for (Index = 0; Index < 32; Index++){
343 if (value & (1 << Index)) break;
344 }
345 return (UINT8) Index;
346}
Edward O'Callaghancb0dd582014-12-07 05:20:14 +1100347
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000348UINT8
349LibAmdBitScanReverse (
350 IN UINT32 value
351)
352{
Edward O'Callaghancb0dd582014-12-07 05:20:14 +1100353 uint8_t bit = 31;
354 do {
355 if (value & (1 << 31))
356 return bit;
357
358 value <<= 1;
359 bit--;
360
361 } while (value != 0);
362
363 return 0xFF; /* Error code indicating no bit found */
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000364}
Edward O'Callaghancb0dd582014-12-07 05:20:14 +1100365
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000366VOID
367LibAmdMsrRead (
368 IN UINT32 MsrAddress,
369 OUT UINT64 *Value,
370 IN OUT AMD_CONFIG_PARAMS *ConfigPtr
371 )
372{
373 *Value = __readmsr (MsrAddress);
374}
375VOID
376LibAmdMsrWrite (
377 IN UINT32 MsrAddress,
Arthur Heymans8d3640d2022-05-16 12:27:36 +0200378 CONST IN UINT64 *Value,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000379 IN OUT AMD_CONFIG_PARAMS *ConfigPtr
380 )
381{
382 __writemsr (MsrAddress, *Value);
383}
384void LibAmdCpuidRead (
385 IN UINT32 CpuidFcnAddress,
386 OUT CPUID_DATA* Value,
387 IN OUT AMD_CONFIG_PARAMS *ConfigPtr
388 )
389{
390 __cpuid ((int *)Value, CpuidFcnAddress);
391}
392UINT64
393ReadTSC (
394 VOID
395 )
396{
397 return __rdtsc ();
398}
efdesign9805a89ab2011-06-20 17:38:49 -0700399VOID
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000400LibAmdSimNowEnterDebugger (
401 VOID
402 )
403{
404 STATIC CONST UINT8 opcode [] = {0x60, // pushad
405 0xBB, 0x02, 0x00, 0x00, 0x00, // mov ebx, 2
406 0xB8, 0x0B, 0xD0, 0xCC, 0xBA, // mov eax, 0xBACCD00B
407 0x0F, 0xA2, // cpuid
408 0x61, // popad
409 0xC3 // ret
410 };
411 ((VOID (*)(VOID)) (size_t) opcode) (); // call the function
412}
Kerry She1c85c772011-05-07 08:37:38 +0000413
414#ifdef __SSE3__
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000415VOID F10RevDProbeFilterCritical (
416 IN PCI_ADDR PciAddress,
417 IN UINT32 PciRegister
418 )
419{
420 UINT64 msrsave;
421 msrsave = __readmsr (0xC001001F);
422 __writemsr (0xC001001F, msrsave | 1ULL << 46); // EnableCf8ExtCfg
423 _mm_mfence ();
424 __outdword (0xCF8, PciAddress.AddressValue);
425 _mm_mfence ();
426 __outdword (0xCFC, PciRegister | 2);
427 _mm_mfence ();
efdesign9805a89ab2011-06-20 17:38:49 -0700428 __writemsr (0xC001001F, msrsave);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000429}
Kerry She1c85c772011-05-07 08:37:38 +0000430
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000431VOID
432LibAmdCLFlush (
433 IN UINT64 Address,
434 IN UINT8 Count
435 )
436{
437 UINT64 hwcrSave;
438 UINT8 *address32;
439 UINTN Index;
440 address32 = 0;
441 hwcrSave = SetFsBase (Address);
442 for (Index = 0; Index < Count; Index++){
443 _mm_mfence ();
444 _mm_clflush_fs (&address32 [Index * 64]);
445 }
446 RestoreHwcr (hwcrSave);
447}
Kerry She1c85c772011-05-07 08:37:38 +0000448#endif //__SSE3__
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000449
Kerry She1c85c772011-05-07 08:37:38 +0000450VOID
Kerry She1c85c772011-05-07 08:37:38 +0000451StopHere (
452 VOID
453 )
454{
455 VOLATILE UINTN x = 1;
456 while (x);
457}
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000458
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300459VOID
460LibAmdFinit()
461{
462 /* TODO: finit */
463 __asm__ volatile ("finit");
464}
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000465/*---------------------------------------------------------------------------------------*/
466/**
467 * Read IO port
468 *
469 *
470 * @param[in] AccessWidth Access width
471 * @param[in] IoAddress IO port address
472 * @param[in] Value Pointer to save data
473 * @param[in] StdHeader Standard configuration header
474 *
475 */
476VOID
477LibAmdIoRead (
478 IN ACCESS_WIDTH AccessWidth,
479 IN UINT16 IoAddress,
480 OUT VOID *Value,
481 IN OUT AMD_CONFIG_PARAMS *StdHeader
482 )
483{
484 switch (AccessWidth) {
485 case AccessWidth8:
486 case AccessS3SaveWidth8:
487 *(UINT8 *) Value = ReadIo8 (IoAddress);
488 break;
489 case AccessWidth16:
490 case AccessS3SaveWidth16:
491 *(UINT16 *) Value = ReadIo16 (IoAddress);
492 break;
493 case AccessWidth32:
494 case AccessS3SaveWidth32:
495 *(UINT32 *) Value = ReadIo32 (IoAddress);
496 break;
497 default:
498 ASSERT (FALSE);
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300499 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000500 }
501}
502
503/*---------------------------------------------------------------------------------------*/
504/**
505 * Write IO port
506 *
507 *
508 * @param[in] AccessWidth Access width
509 * @param[in] IoAddress IO port address
510 * @param[in] Value Pointer to data
511 * @param[in] StdHeader Standard configuration header
512 *
513 */
514VOID
515LibAmdIoWrite (
516 IN ACCESS_WIDTH AccessWidth,
517 IN UINT16 IoAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100518 IN CONST VOID *Value,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000519 IN OUT AMD_CONFIG_PARAMS *StdHeader
520 )
521{
522 switch (AccessWidth) {
523 case AccessWidth8:
524 case AccessS3SaveWidth8:
525 WriteIo8 (IoAddress, *(UINT8 *) Value);
526 break;
527 case AccessWidth16:
528 case AccessS3SaveWidth16:
529 WriteIo16 (IoAddress, *(UINT16 *) Value);
530 break;
531 case AccessWidth32:
532 case AccessS3SaveWidth32:
533 WriteIo32 (IoAddress, *(UINT32 *) Value);
534 break;
535 default:
536 ASSERT (FALSE);
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300537 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000538 }
539}
540
541/*---------------------------------------------------------------------------------------*/
542/**
543 * IO read modify write
544 *
545 *
546 * @param[in] AccessWidth Access width
547 * @param[in] IoAddress IO address
548 * @param[in] Data OR data
549 * @param[in] DataMask Mask to be used before data write back to register.
550 * @param[in] StdHeader Standard configuration header
551 *
552 */
553VOID
554LibAmdIoRMW (
555 IN ACCESS_WIDTH AccessWidth,
556 IN UINT16 IoAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100557 IN CONST VOID *Data,
558 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000559 IN OUT AMD_CONFIG_PARAMS *StdHeader
560 )
561{
efdesign9800c8c4a2011-07-20 12:37:58 -0600562 UINT32 TempData = 0;
563 UINT32 TempMask = 0;
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300564 UINT32 Value = 0;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000565 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
566 LibAmdIoRead (AccessWidth, IoAddress, &Value, StdHeader);
567 Value = (Value & (~TempMask)) | TempData;
568 LibAmdIoWrite (AccessWidth, IoAddress, &Value, StdHeader);
569}
570
571/*---------------------------------------------------------------------------------------*/
572/**
573 * Poll IO register
574 *
575 * Poll register until (RegisterValue & DataMask) == Data
576 *
577 * @param[in] AccessWidth Access width
578 * @param[in] IoAddress IO address
579 * @param[in] Data Data to compare
580 * @param[in] DataMask And mask
581 * @param[in] Delay Poll for time in 100ns (not supported)
582 * @param[in] StdHeader Standard configuration header
583 *
584 */
585VOID
586LibAmdIoPoll (
587 IN ACCESS_WIDTH AccessWidth,
588 IN UINT16 IoAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100589 IN CONST VOID *Data,
590 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000591 IN UINT64 Delay,
592 IN OUT AMD_CONFIG_PARAMS *StdHeader
593 )
594{
efdesign9800c8c4a2011-07-20 12:37:58 -0600595 UINT32 TempData = 0;
596 UINT32 TempMask = 0;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000597 UINT32 Value;
598 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
599 do {
600 LibAmdIoRead (AccessWidth, IoAddress, &Value, StdHeader);
601 } while (TempData != (Value & TempMask));
602}
603
604/*---------------------------------------------------------------------------------------*/
605/**
606 * Read memory/MMIO
607 *
608 *
609 * @param[in] AccessWidth Access width
610 * @param[in] MemAddress Memory address
611 * @param[in] Value Pointer to data
612 * @param[in] StdHeader Standard configuration header
613 *
614 */
615VOID
616LibAmdMemRead (
617 IN ACCESS_WIDTH AccessWidth,
618 IN UINT64 MemAddress,
619 OUT VOID *Value,
620 IN OUT AMD_CONFIG_PARAMS *StdHeader
621 )
622{
623 switch (AccessWidth) {
624 case AccessWidth8:
625 case AccessS3SaveWidth8:
626 *(UINT8 *) Value = Read64Mem8 (MemAddress);
627 break;
628 case AccessWidth16:
629 case AccessS3SaveWidth16:
630 *(UINT16 *) Value = Read64Mem16 (MemAddress);
631 break;
632 case AccessWidth32:
633 case AccessS3SaveWidth32:
634 *(UINT32 *) Value = Read64Mem32 (MemAddress);
635 break;
636 default:
637 ASSERT (FALSE);
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300638 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000639 }
640}
641
642/*---------------------------------------------------------------------------------------*/
643/**
644 * Write memory/MMIO
645 *
646 *
647 * @param[in] AccessWidth Access width
648 * @param[in] MemAddress Memory address
649 * @param[in] Value Pointer to data
650 * @param[in] StdHeader Standard configuration header
651 *
652 */
653VOID
654LibAmdMemWrite (
655 IN ACCESS_WIDTH AccessWidth,
656 IN UINT64 MemAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100657 IN CONST VOID *Value,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000658 IN OUT AMD_CONFIG_PARAMS *StdHeader
659 )
660{
661
662 switch (AccessWidth) {
663 case AccessWidth8:
664 case AccessS3SaveWidth8:
665 Write64Mem8 (MemAddress, *((UINT8 *) Value));
666 break;
667 case AccessWidth16:
668 case AccessS3SaveWidth16:
669 Write64Mem16 (MemAddress, *((UINT16 *) Value));
670 break;
671 case AccessWidth32:
672 case AccessS3SaveWidth32:
673 Write64Mem32 (MemAddress, *((UINT32 *) Value));
674 break;
675 default:
676 ASSERT (FALSE);
Kyösti Mälkki08311f52016-04-19 07:17:59 +0300677 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000678 }
679}
680/*---------------------------------------------------------------------------------------*/
681/**
682 * Memory/MMIO read modify write
683 *
684 *
685 * @param[in] AccessWidth Access width
686 * @param[in] MemAddress Memory address
687 * @param[in] Data OR data
688 * @param[in] DataMask Mask to be used before data write back to register.
689 * @param[in] StdHeader Standard configuration header
690 *
691 */
692VOID
693LibAmdMemRMW (
694 IN ACCESS_WIDTH AccessWidth,
695 IN UINT64 MemAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100696 IN CONST VOID *Data,
697 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000698 IN OUT AMD_CONFIG_PARAMS *StdHeader
699 )
700{
efdesign9800c8c4a2011-07-20 12:37:58 -0600701 UINT32 TempData = 0;
702 UINT32 TempMask = 0;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000703 UINT32 Value;
704 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
705 LibAmdMemRead (AccessWidth, MemAddress, &Value, StdHeader);
706 Value = (Value & (~TempMask)) | TempData;
707 LibAmdMemWrite (AccessWidth, MemAddress, &Value, StdHeader);
708}
709
710/*---------------------------------------------------------------------------------------*/
711/**
712 * Poll Mmio
713 *
714 * Poll register until (RegisterValue & DataMask) == Data
715 *
716 * @param[in] AccessWidth Access width
717 * @param[in] MemAddress Memory address
718 * @param[in] Data Data to compare
719 * @param[in] DataMask AND mask
720 * @param[in] Delay Poll for time in 100ns (not supported)
721 * @param[in] StdHeader Standard configuration header
722 *
723 */
724VOID
725LibAmdMemPoll (
726 IN ACCESS_WIDTH AccessWidth,
727 IN UINT64 MemAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100728 IN CONST VOID *Data,
729 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000730 IN UINT64 Delay,
731 IN OUT AMD_CONFIG_PARAMS *StdHeader
732 )
733{
efdesign9800c8c4a2011-07-20 12:37:58 -0600734 UINT32 TempData = 0;
735 UINT32 TempMask = 0;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000736 UINT32 Value;
737 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
738 do {
739 LibAmdMemRead (AccessWidth, MemAddress, &Value, StdHeader);
740 } while (TempData != (Value & TempMask));
741}
742
743/*---------------------------------------------------------------------------------------*/
744/**
745 * Read PCI config space
746 *
747 *
748 * @param[in] AccessWidth Access width
749 * @param[in] PciAddress Pci address
750 * @param[in] Value Pointer to data
751 * @param[in] StdHeader Standard configuration header
752 *
753 */
754VOID
755LibAmdPciRead (
756 IN ACCESS_WIDTH AccessWidth,
757 IN PCI_ADDR PciAddress,
758 OUT VOID *Value,
759 IN OUT AMD_CONFIG_PARAMS *StdHeader
760 )
761{
762 UINT32 LegacyPciAccess;
763 UINT32 MMIOSize;
764 UINT64 RMWrite;
765 UINT64 RMWritePrevious;
766 UINT64 MMIOAddress;
767
768 ASSERT (StdHeader != NULL);
769 ASSERT (PciAddress.AddressValue != ILLEGAL_SBDFO);
770 if (!GetPciMmioAddress (&MMIOAddress, &MMIOSize, StdHeader)) {
771 // We need to convert our "portable" PCI address into a "real" PCI access
772 LegacyPciAccess = ((1 << 31) + (PciAddress.Address.Register & 0xFC) + (PciAddress.Address.Function << 8) + (PciAddress.Address.Device << 11) + (PciAddress.Address.Bus << 16) + ((PciAddress.Address.Register & 0xF00) << (24 - 8)));
773 if (PciAddress.Address.Register <= 0xFF) {
774 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, StdHeader);
775 LibAmdIoRead (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, StdHeader);
776 } else {
777 LibAmdMsrRead (NB_CFG, &RMWritePrevious, StdHeader);
efdesign9805a89ab2011-06-20 17:38:49 -0700778 RMWrite = RMWritePrevious | 0x0000400000000000ull;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000779 LibAmdMsrWrite (NB_CFG, &RMWrite, StdHeader);
780 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, StdHeader);
781 LibAmdIoRead (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, StdHeader);
782 LibAmdMsrWrite (NB_CFG, &RMWritePrevious, StdHeader);
783 }
784 } else {
785 // Setup the MMIO address
786 ASSERT ((MMIOAddress + MMIOSize) > (MMIOAddress + (PciAddress.AddressValue & 0x0FFFFFFF)));
787 MMIOAddress += (PciAddress.AddressValue & 0x0FFFFFFF);
788 LibAmdMemRead (AccessWidth, MMIOAddress, Value, StdHeader);
789 }
790}
791
792/*---------------------------------------------------------------------------------------*/
793/**
794 * Write PCI config space
795 *
796 *
797 * @param[in] AccessWidth Access width
798 * @param[in] PciAddress Pci address
799 * @param[in] Value Pointer to data
800 * @param[in] StdHeader Standard configuration header
801 *
802 */
803VOID
804LibAmdPciWrite (
805 IN ACCESS_WIDTH AccessWidth,
806 IN PCI_ADDR PciAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100807 IN CONST VOID *Value,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000808 IN OUT AMD_CONFIG_PARAMS *StdHeader
809 )
810{
811 UINT32 LegacyPciAccess;
812 UINT32 MMIOSize;
813 UINT64 RMWrite;
814 UINT64 RMWritePrevious;
815 UINT64 MMIOAddress;
816
817 ASSERT (StdHeader != NULL);
818 ASSERT (PciAddress.AddressValue != ILLEGAL_SBDFO);
819 if (!GetPciMmioAddress (&MMIOAddress, &MMIOSize, StdHeader)) {
820 // We need to convert our "portable" PCI address into a "real" PCI access
821 LegacyPciAccess = ((1 << 31) + (PciAddress.Address.Register & 0xFC) + (PciAddress.Address.Function << 8) + (PciAddress.Address.Device << 11) + (PciAddress.Address.Bus << 16) + ((PciAddress.Address.Register & 0xF00) << (24 - 8)));
822 if (PciAddress.Address.Register <= 0xFF) {
823 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, StdHeader);
824 LibAmdIoWrite (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, StdHeader);
825 } else {
826 LibAmdMsrRead (NB_CFG, &RMWritePrevious, StdHeader);
efdesign9805a89ab2011-06-20 17:38:49 -0700827 RMWrite = RMWritePrevious | 0x0000400000000000ull;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000828 LibAmdMsrWrite (NB_CFG, &RMWrite, StdHeader);
829 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, StdHeader);
830 LibAmdIoWrite (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, StdHeader);
831 LibAmdMsrWrite (NB_CFG, &RMWritePrevious, StdHeader);
832 }
833 } else {
834 // Setup the MMIO address
835 ASSERT ((MMIOAddress + MMIOSize) > (MMIOAddress + (PciAddress.AddressValue & 0x0FFFFFFF)));
836 MMIOAddress += (PciAddress.AddressValue & 0x0FFFFFFF);
837 LibAmdMemWrite (AccessWidth, MMIOAddress, Value, StdHeader);
838 }
839}
840
841/*---------------------------------------------------------------------------------------*/
842/**
843 * PCI read modify write
844 *
845 *
846 * @param[in] AccessWidth Access width
847 * @param[in] PciAddress Pci address
848 * @param[in] Data OR Data
849 * @param[in] DataMask Mask to be used before data write back to register.
850 * @param[in] StdHeader Standard configuration header
851 *
852 */
853VOID
854LibAmdPciRMW (
855 IN ACCESS_WIDTH AccessWidth,
856 IN PCI_ADDR PciAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100857 IN CONST VOID *Data,
858 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000859 IN OUT AMD_CONFIG_PARAMS *StdHeader
860 )
861{
efdesign9800c8c4a2011-07-20 12:37:58 -0600862 UINT32 TempData = 0;
863 UINT32 TempMask = 0;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000864 UINT32 Value;
865 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
866 LibAmdPciRead (AccessWidth, PciAddress, &Value, StdHeader);
867 Value = (Value & (~TempMask)) | TempData;
868 LibAmdPciWrite (AccessWidth, PciAddress, &Value, StdHeader);
869}
870
871/*---------------------------------------------------------------------------------------*/
872/**
873 * Poll PCI config space register
874 *
875 * Poll register until (RegisterValue & DataMask) == Data
876 *
877 * @param[in] AccessWidth Access width
878 * @param[in] PciAddress Pci address
879 * @param[in] Data Data to compare
880 * @param[in] DataMask AND mask
881 * @param[in] Delay Poll for time in 100ns (not supported)
882 * @param[in] StdHeader Standard configuration header
883 *
884 */
885VOID
886LibAmdPciPoll (
887 IN ACCESS_WIDTH AccessWidth,
888 IN PCI_ADDR PciAddress,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100889 IN CONST VOID *Data,
890 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000891 IN UINT64 Delay,
892 IN OUT AMD_CONFIG_PARAMS *StdHeader
893 )
894{
efdesign9800c8c4a2011-07-20 12:37:58 -0600895 UINT32 TempData = 0;
896 UINT32 TempMask = 0;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000897 UINT32 Value;
898 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
899 do {
900 LibAmdPciRead (AccessWidth, PciAddress, &Value, StdHeader);
901 } while (TempData != (Value & TempMask));
902}
903
904/*---------------------------------------------------------------------------------------*/
905/**
906 * Get MMIO base address for PCI accesses
907 *
908 * @param[out] MmioAddress PCI MMIO base address
909 * @param[out] MmioSize Size of region in bytes
910 * @param[in] StdHeader Standard configuration header
911 *
912 * @retval TRUE MmioAddress/MmioSize are valid
913 */
914BOOLEAN
915STATIC
916GetPciMmioAddress (
917 OUT UINT64 *MmioAddress,
918 OUT UINT32 *MmioSize,
919 IN AMD_CONFIG_PARAMS *StdHeader
920 )
921{
922 BOOLEAN MmioIsEnabled;
923 UINT32 EncodedSize;
924 UINT64 MsrReg;
925
926 ASSERT (StdHeader != NULL);
927
928 MmioIsEnabled = FALSE;
929 LibAmdMsrRead (MSR_MMIO_Cfg_Base, &MsrReg, StdHeader);
930 if ((MsrReg & BIT0) != 0) {
efdesign9805a89ab2011-06-20 17:38:49 -0700931 *MmioAddress = MsrReg & 0xFFFFFFFFFFF00000ull;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000932 EncodedSize = (UINT32) ((MsrReg & 0x3C) >> 2);
933 *MmioSize = ((1 << EncodedSize) * 0x100000);
934 MmioIsEnabled = TRUE;
935 }
936 return MmioIsEnabled;
937}
938
939/*---------------------------------------------------------------------------------------*/
940/**
941 * Read field of PCI config register.
942 *
943 *
944 *
945 * @param[in] Address Pci address (register must be DWORD aligned)
946 * @param[in] Highbit High bit position of the field in DWORD
947 * @param[in] Lowbit Low bit position of the field in DWORD
948 * @param[out] Value Pointer to data
949 * @param[in] StdHeader Standard configuration header
950 */
951VOID
952LibAmdPciReadBits (
953 IN PCI_ADDR Address,
954 IN UINT8 Highbit,
955 IN UINT8 Lowbit,
956 OUT UINT32 *Value,
957 IN AMD_CONFIG_PARAMS *StdHeader
958 )
959{
960 ASSERT (Highbit < 32 && Lowbit < 32 && Highbit >= Lowbit && (Address.AddressValue & 3) == 0);
961
962 LibAmdPciRead (AccessWidth32, Address, Value, StdHeader);
963 *Value >>= Lowbit; // Shift
964
965 // A 1 << 32 == 1 << 0 due to x86 SHL instruction, so skip if that is the case
966
967 if ((Highbit - Lowbit) != 31) {
968 *Value &= (((UINT32) 1 << (Highbit - Lowbit + 1)) - 1);
969 }
970}
971
972/*---------------------------------------------------------------------------------------*/
973/**
974 * Write field of PCI config register.
975 *
976 *
977 *
978 * @param[in] Address Pci address (register must be DWORD aligned)
979 * @param[in] Highbit High bit position of the field in DWORD
980 * @param[in] Lowbit Low bit position of the field in DWORD
981 * @param[in] Value Pointer to data
982 * @param[in] StdHeader Standard configuration header
983 */
984VOID
985LibAmdPciWriteBits (
986 IN PCI_ADDR Address,
987 IN UINT8 Highbit,
988 IN UINT8 Lowbit,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +1100989 IN CONST UINT32 *Value,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000990 IN AMD_CONFIG_PARAMS *StdHeader
991 )
992{
993 UINT32 Temp;
994 UINT32 Mask;
995
996 ASSERT (Highbit < 32 && Lowbit < 32 && Highbit >= Lowbit && (Address.AddressValue & 3) == 0);
997
998 // A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case
999
1000 if ((Highbit - Lowbit) != 31) {
1001 Mask = (((UINT32) 1 << (Highbit - Lowbit + 1)) - 1);
1002 } else {
1003 Mask = (UINT32) 0xFFFFFFFF;
1004 }
1005
1006 LibAmdPciRead (AccessWidth32, Address, &Temp, StdHeader);
1007 Temp &= ~(Mask << Lowbit);
1008 Temp |= (*Value & Mask) << Lowbit;
1009 LibAmdPciWrite (AccessWidth32, Address, &Temp, StdHeader);
1010}
1011
1012/*---------------------------------------------------------------------------------------*/
1013/**
1014 * Locate next capability pointer
1015 *
1016 * Given a SBDFO this routine will find the next PCI capabilities list entry.
1017 * if the end of the list is reached, or if a problem is detected, then ILLEGAL_SBDFO is
1018 * returned.
1019 * To start a new search from the head of the list, specify a SBDFO with an offset of zero.
1020 *
1021 * @param[in,out] Address Pci address
1022 * @param[in] StdHeader Standard configuration header
1023 */
1024
1025VOID
1026LibAmdPciFindNextCap (
1027 IN OUT PCI_ADDR *Address,
1028 IN AMD_CONFIG_PARAMS *StdHeader
1029 )
1030{
1031 PCI_ADDR Base;
1032 UINT32 Offset;
1033 UINT32 Temp;
1034 PCI_ADDR TempAddress;
1035
1036 ASSERT (Address != NULL);
1037 ASSERT (*(UINT32 *) Address != ILLEGAL_SBDFO);
1038
1039 Base.AddressValue = Address->AddressValue;
1040 Offset = Base.Address.Register;
1041 Base.Address.Register = 0;
1042
1043 Address->AddressValue = (UINT32) ILLEGAL_SBDFO;
1044
1045 // Verify that the SBDFO points to a valid PCI device SANITY CHECK
1046 LibAmdPciRead (AccessWidth32, Base, &Temp, StdHeader);
1047 if (Temp == 0xFFFFFFFF) {
1048 ASSERT (FALSE);
1049 return; // There is no device at this address
1050 }
1051
1052 // Verify that the device supports a capability list
1053 TempAddress.AddressValue = Base.AddressValue + 0x04;
1054 LibAmdPciReadBits (TempAddress, 20, 20, &Temp, StdHeader);
1055 if (Temp == 0) {
1056 return; // This PCI device does not support capability lists
1057 }
1058
1059 if (Offset != 0) {
1060 // If we are continuing on an existing list
1061 TempAddress.AddressValue = Base.AddressValue + Offset;
1062 LibAmdPciReadBits (TempAddress, 15, 8, &Temp, StdHeader);
1063 } else {
1064 // We are starting on a new list
1065 TempAddress.AddressValue = Base.AddressValue + 0x34;
1066 LibAmdPciReadBits (TempAddress, 7, 0, &Temp, StdHeader);
1067 }
1068
1069 if (Temp == 0) {
1070 return; // We have reached the end of the capabilities list
1071 }
1072
1073 // Error detection and recovery- The statement below protects against
1074 // PCI devices with broken PCI capabilities lists. Detect a pointer
1075 // that is not uint32 aligned, points into the first 64 reserved DWORDs
1076 // or points back to itself.
1077 if (((Temp & 3) != 0) || (Temp == Offset) || (Temp < 0x40)) {
1078 ASSERT (FALSE);
1079 return;
1080 }
1081
1082 Address->AddressValue = Base.AddressValue + Temp;
1083 return;
1084}
1085
1086/*---------------------------------------------------------------------------------------*/
1087/**
1088 * Set memory with value
1089 *
1090 *
1091 * @param[in,out] Destination Pointer to memory range
1092 * @param[in] Value Value to set memory with
1093 * @param[in] FillLength Size of the memory range
1094 * @param[in] StdHeader Standard configuration header (Optional)
1095 */
1096VOID
1097LibAmdMemFill (
1098 IN VOID *Destination,
1099 IN UINT8 Value,
1100 IN UINTN FillLength,
1101 IN OUT AMD_CONFIG_PARAMS *StdHeader
1102 )
1103{
1104 UINT8 *Dest;
1105 ASSERT (StdHeader != NULL);
1106 Dest = Destination;
1107 while ((FillLength--) != 0) {
1108 *Dest++ = Value;
1109 }
1110}
1111
1112/*---------------------------------------------------------------------------------------*/
1113/**
1114 * Copy memory
1115 *
1116 *
1117 * @param[in,out] Destination Pointer to destination buffer
1118 * @param[in] Source Pointer to source buffer
1119 * @param[in] CopyLength buffer length
1120 * @param[in] StdHeader Standard configuration header (Optional)
1121 */
1122VOID
1123LibAmdMemCopy (
1124 IN VOID *Destination,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +11001125 IN CONST VOID *Source,
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001126 IN UINTN CopyLength,
1127 IN OUT AMD_CONFIG_PARAMS *StdHeader
1128 )
1129{
1130 UINT8 *Dest;
Edward O'Callaghan3e570d42014-11-09 11:43:59 +11001131 CONST UINT8 *SourcePtr;
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001132 ASSERT (StdHeader != NULL);
1133 Dest = Destination;
1134 SourcePtr = Source;
1135 while ((CopyLength--) != 0) {
1136 *Dest++ = *SourcePtr++;
1137 }
1138}
1139
1140/*---------------------------------------------------------------------------------------*/
1141/**
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001142 * Returns the package type mask for the processor
1143 *
1144 *
1145 * @param[in] StdHeader Standard configuration header (Optional)
1146 */
1147
1148// Returns the package type mask for the processor
1149UINT32
1150LibAmdGetPackageType (
1151 IN AMD_CONFIG_PARAMS *StdHeader
1152 )
1153{
1154 UINT32 ProcessorPackageType;
1155 CPUID_DATA CpuId;
1156
1157 LibAmdCpuidRead (0x80000001, &CpuId, StdHeader);
1158 ProcessorPackageType = (UINT32) (CpuId.EBX_Reg >> 28) & 0xF; // bit 31:28
1159 return (UINT32) (1 << ProcessorPackageType);
1160}
1161
1162/*---------------------------------------------------------------------------------------*/
1163/**
1164 * Returns the package type mask for the processor
1165 *
1166 *
1167 * @param[in] AccessWidth Access width
1168 * @param[in] Data data
1169 * @param[in] DataMask data
1170 * @param[out] TemData typecast data
1171 * @param[out] TempDataMask typecast data
1172 */
1173
1174
1175VOID
1176STATIC
1177LibAmdGetDataFromPtr (
1178 IN ACCESS_WIDTH AccessWidth,
Edward O'Callaghan3e570d42014-11-09 11:43:59 +11001179 IN CONST VOID *Data,
1180 IN CONST VOID *DataMask,
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001181 OUT UINT32 *TemData,
1182 OUT UINT32 *TempDataMask
1183 )
1184{
1185 switch (AccessWidth) {
1186 case AccessWidth8:
1187 case AccessS3SaveWidth8:
1188 *TemData = (UINT32)*(UINT8 *) Data;
1189 *TempDataMask = (UINT32)*(UINT8 *) DataMask;
1190 break;
1191 case AccessWidth16:
1192 case AccessS3SaveWidth16:
1193 *TemData = (UINT32)*(UINT16 *) Data;
1194 *TempDataMask = (UINT32)*(UINT16 *) DataMask;
1195 break;
1196 case AccessWidth32:
1197 case AccessS3SaveWidth32:
1198 *TemData = *(UINT32 *) Data;
1199 *TempDataMask = *(UINT32 *) DataMask;
1200 break;
1201 default:
1202 IDS_ERROR_TRAP;
Kyösti Mälkki08311f52016-04-19 07:17:59 +03001203 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001204 }
1205}
1206
1207/*---------------------------------------------------------------------------------------*/
1208/**
1209 * Returns the package type mask for the processor
1210 *
1211 *
1212 * @param[in] AccessWidth Access width
1213 * @retval Width in number of bytes
1214 */
1215
1216
1217UINT8
1218LibAmdAccessWidth (
1219 IN ACCESS_WIDTH AccessWidth
1220 )
1221{
1222 UINT8 Width;
1223
1224 switch (AccessWidth) {
1225 case AccessWidth8:
1226 case AccessS3SaveWidth8:
1227 Width = 1;
1228 break;
1229 case AccessWidth16:
1230 case AccessS3SaveWidth16:
1231 Width = 2;
1232 break;
1233 case AccessWidth32:
1234 case AccessS3SaveWidth32:
1235 Width = 4;
1236 break;
1237 case AccessWidth64:
1238 case AccessS3SaveWidth64:
1239 Width = 8;
1240 break;
1241 default:
1242 Width = 0;
1243 IDS_ERROR_TRAP;
Kyösti Mälkki08311f52016-04-19 07:17:59 +03001244 break;
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001245 }
1246 return Width;
1247}
1248
efdesign9805a89ab2011-06-20 17:38:49 -07001249VOID
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001250CpuidRead (
1251 IN UINT32 CpuidFcnAddress,
1252 OUT CPUID_DATA *Value
1253 )
1254{
1255 __cpuid ((int *)Value, CpuidFcnAddress);
1256}
1257
efdesign9805a89ab2011-06-20 17:38:49 -07001258UINT8
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001259ReadNumberOfCpuCores(
1260 VOID
1261 )
1262{
1263 CPUID_DATA Value;
1264 CpuidRead (0x80000008, &Value);
efdesign9805a89ab2011-06-20 17:38:49 -07001265 return Value.ECX_Reg & 0xff;
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001266}