drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / src / vendorcode / amd / pi / Lib / amdlib.c
blobec3b53b017099139b8edb2360b7876e8c0c813df
1 /* $NoKeywords:$ */
2 /**
3 * @file
5 * AMD Library
7 * Contains interface to the AMD AGESA library
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: Lib
12 * @e \$Revision: 48409 $ @e \$Date: 2011-03-08 11:19:40 -0600 (Tue, 08 Mar 2011) $
16 ******************************************************************************
18 * Copyright (c) 2008 - 2011, Advanced Micro Devices, Inc.
19 * 2013 - 2014, Sage Electronic Engineering, LLC
20 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 * * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * * Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
30 * its contributors may be used to endorse or promote products derived
31 * from this software without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
37 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 ******************************************************************************
46 #include <AGESA.h>
47 #include <cpuRegisters.h>
48 #include <cpu/x86/mp.h>
49 #include <cpu/x86/cache.h>
50 #include <Filecode.h>
51 #include <Ids.h>
52 #include <Porting.h>
53 #include "amdlib.h"
54 CODE_GROUP (G1_PEICC)
55 RDATA_GROUP (G1_PEICC)
57 #if !defined(AMDLIB_OPTIMIZE)
58 #define AMDLIB_OPTIMIZE
59 #endif
61 #define FILECODE LIB_AMDLIB_FILECODE
63 STATIC
64 BOOLEAN
65 GetPciMmioAddress (
66 OUT UINT64 *MmioAddress,
67 OUT UINT32 *MmioSize,
68 IN AMD_CONFIG_PARAMS *StdHeader
71 STATIC
72 VOID
73 LibAmdGetDataFromPtr (
74 IN ACCESS_WIDTH AccessWidth,
75 IN CONST VOID *Data,
76 IN CONST VOID *DataMask,
77 OUT UINT32 *TemData,
78 OUT UINT32 *TempDataMask
80 VOID
81 IdsOutPort (
82 IN UINT32 Addr,
83 IN UINT32 Value,
84 IN UINT32 Flag
87 VOID
88 CpuidRead (
89 IN UINT32 CpuidFcnAddress,
90 OUT CPUID_DATA *Value
93 UINT8
94 ReadNumberOfCpuCores(
95 void
98 AMDLIB_OPTIMIZE
99 UINT8
100 ReadIo8 (
101 IN UINT16 Address
104 return __inbyte (Address);
107 AMDLIB_OPTIMIZE
108 UINT16
109 ReadIo16 (
110 IN UINT16 Address
113 return __inword (Address);
116 AMDLIB_OPTIMIZE
117 UINT32
118 ReadIo32 (
119 IN UINT16 Address
122 return __indword (Address);
125 AMDLIB_OPTIMIZE
126 VOID
127 WriteIo8 (
128 IN UINT16 Address,
129 IN UINT8 Data
132 __outbyte (Address, Data);
135 AMDLIB_OPTIMIZE
136 VOID
137 WriteIo16 (
138 IN UINT16 Address,
139 IN UINT16 Data
142 __outword (Address, Data);
145 AMDLIB_OPTIMIZE
146 VOID
147 WriteIo32 (
148 IN UINT16 Address,
149 IN UINT32 Data
152 __outdword (Address, Data);
155 STATIC
156 AMDLIB_OPTIMIZE
157 UINT64 SetFsBase (
158 UINT64 address
161 UINT64 hwcr;
162 hwcr = __readmsr (0xC0010015);
163 __writemsr (0xC0010015, hwcr | 1 << 17);
164 __writemsr (0xC0000100, address);
165 return hwcr;
168 STATIC
169 AMDLIB_OPTIMIZE
170 VOID
171 RestoreHwcr (
172 UINT64
173 value
176 __writemsr (0xC0010015, value);
179 AMDLIB_OPTIMIZE
180 UINT8
181 Read64Mem8 (
182 IN UINT64 Address
185 UINT8 dataRead;
186 UINT64 hwcrSave;
187 if ((Address >> 32) == 0) {
188 return *(volatile UINT8 *) (UINTN) Address;
190 hwcrSave = SetFsBase (Address);
191 dataRead = __readfsbyte (0);
192 RestoreHwcr (hwcrSave);
193 return dataRead;
196 AMDLIB_OPTIMIZE
197 UINT16
198 Read64Mem16 (
199 IN UINT64 Address
202 UINT16 dataRead;
203 UINT64 hwcrSave;
204 if ((Address >> 32) == 0) {
205 return *(volatile UINT16 *) (UINTN) Address;
207 hwcrSave = SetFsBase (Address);
208 dataRead = __readfsword (0);
209 RestoreHwcr (hwcrSave);
210 return dataRead;
213 AMDLIB_OPTIMIZE
214 UINT32
215 Read64Mem32 (
216 IN UINT64 Address
219 UINT32 dataRead;
220 UINT64 hwcrSave;
221 if ((Address >> 32) == 0) {
222 return *(volatile UINT32 *) (UINTN) Address;
224 hwcrSave = SetFsBase (Address);
225 dataRead = __readfsdword (0);
226 RestoreHwcr (hwcrSave);
227 return dataRead;
230 AMDLIB_OPTIMIZE
231 VOID
232 Write64Mem8 (
233 IN UINT64 Address,
234 IN UINT8 Data
237 if ((Address >> 32) == 0){
238 *(volatile UINT8 *) (UINTN) Address = Data;
240 else {
241 UINT64 hwcrSave;
242 hwcrSave = SetFsBase (Address);
243 __writefsbyte (0, Data);
244 RestoreHwcr (hwcrSave);
248 AMDLIB_OPTIMIZE
249 VOID
250 Write64Mem16 (
251 IN UINT64 Address,
252 IN UINT16 Data
255 if ((Address >> 32) == 0){
256 *(volatile UINT16 *) (UINTN) Address = Data;
258 else {
259 UINT64 hwcrSave;
260 hwcrSave = SetFsBase (Address);
261 __writefsword (0, Data);
262 RestoreHwcr (hwcrSave);
266 AMDLIB_OPTIMIZE
267 VOID
268 Write64Mem32 (
269 IN UINT64 Address,
270 IN UINT32 Data
273 if ((Address >> 32) == 0){
274 *(volatile UINT32 *) (UINTN) Address = Data;
276 else {
277 UINT64 hwcrSave;
278 hwcrSave = SetFsBase (Address);
279 __writefsdword (0, Data);
280 RestoreHwcr (hwcrSave);
284 AMDLIB_OPTIMIZE
285 VOID
286 LibAmdReadCpuReg (
287 IN UINT8 RegNum,
288 OUT UINT32 *Value
291 *Value = 0;
292 switch (RegNum){
293 case CR4_REG:
294 *Value = __readcr4 ();
295 break;
296 case DR0_REG:
297 *Value = __readdr (0);
298 break;
299 case DR1_REG:
300 *Value = __readdr (1);
301 break;
302 case DR2_REG:
303 *Value = __readdr (2);
304 break;
305 case DR3_REG:
306 *Value = __readdr (3);
307 break;
308 case DR7_REG:
309 *Value = __readdr (7);
310 break;
311 default:
312 *Value = -1;
313 break;
317 AMDLIB_OPTIMIZE
318 VOID
319 LibAmdWriteCpuReg (
320 IN UINT8 RegNum,
321 IN UINT32 Value
324 switch (RegNum){
325 case CR4_REG:
326 __writecr4 (Value);
327 break;
328 case DR0_REG:
329 __writedr (0, Value);
330 break;
331 case DR1_REG:
332 __writedr (1, Value);
333 break;
334 case DR2_REG:
335 __writedr (2, Value);
336 break;
337 case DR3_REG:
338 __writedr (3, Value);
339 break;
340 case DR7_REG:
341 __writedr (7, Value);
342 break;
343 default:
344 break;
348 AMDLIB_OPTIMIZE
349 VOID
350 LibAmdWriteBackInvalidateCache (
351 void
354 __wbinvd ();
357 AMDLIB_OPTIMIZE
358 VOID
359 LibAmdHDTBreakPoint (
360 void
363 __writemsr (0xC001100A, __readmsr (0xC001100A) | 1);
364 __debugbreak (); // do you really need icebp? If so, go back to asm code
367 AMDLIB_OPTIMIZE
368 UINT8
369 LibAmdBitScanForward (
370 IN UINT32 value
373 UINTN Index;
374 for (Index = 0; Index < 32; Index++){
375 if (value & (1 << Index)) break;
377 return (UINT8) Index;
380 AMDLIB_OPTIMIZE
381 UINT8
382 LibAmdBitScanReverse (
383 IN UINT32 value
386 uint8_t bit = 31;
387 do {
388 if (value & (1 << 31))
389 return bit;
391 value <<= 1;
392 bit--;
394 } while (value != 0);
396 return 0xFF; /* Error code indicating no bit found */
399 AMDLIB_OPTIMIZE
400 VOID
401 LibAmdMsrRead (
402 IN UINT32 MsrAddress,
403 OUT UINT64 *Value,
404 IN OUT AMD_CONFIG_PARAMS *ConfigPtr
407 if ((MsrAddress == 0xFFFFFFFF) || (MsrAddress == 0x00000000)) {
408 IdsErrorStop(MsrAddress);
410 *Value = __readmsr (MsrAddress);
413 AMDLIB_OPTIMIZE
414 VOID
415 LibAmdMsrWrite (
416 IN UINT32 MsrAddress,
417 IN UINT64 *Value,
418 IN OUT AMD_CONFIG_PARAMS *ConfigPtr
421 __writemsr (MsrAddress, *Value);
424 AMDLIB_OPTIMIZE
425 void LibAmdCpuidRead (
426 IN UINT32 CpuidFcnAddress,
427 OUT CPUID_DATA* Value,
428 IN OUT AMD_CONFIG_PARAMS *ConfigPtr
431 __cpuid ((int *)Value, CpuidFcnAddress);
434 AMDLIB_OPTIMIZE
435 UINT64
436 ReadTSC (
437 void
440 return __rdtsc ();
443 AMDLIB_OPTIMIZE
444 VOID
445 LibAmdSimNowEnterDebugger (
446 void
449 STATIC CONST UINT8 opcode [] = {0x60, // pushad
450 0xBB, 0x02, 0x00, 0x00, 0x00, // mov ebx, 2
451 0xB8, 0x0B, 0xD0, 0xCC, 0xBA, // mov eax, 0xBACCD00B
452 0x0F, 0xA2, // cpuid
453 0x61, // popad
454 0xC3 // ret
456 ((VOID (*)(VOID)) (size_t) opcode) (); // call the function
459 AMDLIB_OPTIMIZE
460 VOID
461 IdsOutPort (
462 IN UINT32 Addr,
463 IN UINT32 Value,
464 IN UINT32 Flag
467 __outdword ((UINT16) Addr, Value);
470 AMDLIB_OPTIMIZE
471 VOID
472 StopHere (
473 void
476 VOLATILE UINTN x = 1;
477 while (x);
480 AMDLIB_OPTIMIZE
481 VOID
482 LibAmdCLFlush (
483 IN UINT64 Address,
484 IN UINT8 Count
487 UINT64 hwcrSave;
488 UINT8 *address32;
489 UINTN Index;
490 address32 = 0;
491 hwcrSave = SetFsBase (Address);
492 for (Index = 0; Index < Count; Index++){
493 mfence();
494 clflush(&address32 [Index * 64]);
496 RestoreHwcr (hwcrSave);
500 AMDLIB_OPTIMIZE
501 VOID
502 LibAmdFinit(
503 void
506 /* TODO: finit */
507 __asm__ volatile ("finit");
509 /*---------------------------------------------------------------------------------------*/
511 * Read IO port
514 * @param[in] AccessWidth Access width
515 * @param[in] IoAddress IO port address
516 * @param[in] Value Pointer to save data
517 * @param[in] StdHeader Standard configuration header
520 VOID
521 LibAmdIoRead (
522 IN ACCESS_WIDTH AccessWidth,
523 IN UINT16 IoAddress,
524 OUT VOID *Value,
525 IN OUT AMD_CONFIG_PARAMS *StdHeader
528 switch (AccessWidth) {
529 case AccessWidth8:
530 case AccessS3SaveWidth8:
531 *(UINT8 *) Value = ReadIo8 (IoAddress);
532 break;
533 case AccessWidth16:
534 case AccessS3SaveWidth16:
535 *(UINT16 *) Value = ReadIo16 (IoAddress);
536 break;
537 case AccessWidth32:
538 case AccessS3SaveWidth32:
539 *(UINT32 *) Value = ReadIo32 (IoAddress);
540 break;
541 default:
542 ASSERT (FALSE);
543 break;
547 /*---------------------------------------------------------------------------------------*/
549 * Write IO port
552 * @param[in] AccessWidth Access width
553 * @param[in] IoAddress IO port address
554 * @param[in] Value Pointer to data
555 * @param[in] StdHeader Standard configuration header
558 VOID
559 LibAmdIoWrite (
560 IN ACCESS_WIDTH AccessWidth,
561 IN UINT16 IoAddress,
562 IN CONST VOID *Value,
563 IN OUT AMD_CONFIG_PARAMS *StdHeader
566 switch (AccessWidth) {
567 case AccessWidth8:
568 case AccessS3SaveWidth8:
569 WriteIo8 (IoAddress, *(UINT8 *) Value);
570 break;
571 case AccessWidth16:
572 case AccessS3SaveWidth16:
573 WriteIo16 (IoAddress, *(UINT16 *) Value);
574 break;
575 case AccessWidth32:
576 case AccessS3SaveWidth32:
577 WriteIo32 (IoAddress, *(UINT32 *) Value);
578 break;
579 default:
580 ASSERT (FALSE);
581 break;
585 /*---------------------------------------------------------------------------------------*/
587 * IO read modify write
590 * @param[in] AccessWidth Access width
591 * @param[in] IoAddress IO address
592 * @param[in] Data OR data
593 * @param[in] DataMask Mask to be used before data write back to register.
594 * @param[in] StdHeader Standard configuration header
597 VOID
598 LibAmdIoRMW (
599 IN ACCESS_WIDTH AccessWidth,
600 IN UINT16 IoAddress,
601 IN CONST VOID *Data,
602 IN CONST VOID *DataMask,
603 IN OUT AMD_CONFIG_PARAMS *StdHeader
606 UINT32 TempData;
607 UINT32 TempMask;
608 UINT32 Value;
609 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
610 LibAmdIoRead (AccessWidth, IoAddress, &Value, NULL);
611 Value = (Value & (~TempMask)) | TempData;
612 LibAmdIoWrite (AccessWidth, IoAddress, &Value, NULL);
615 /*---------------------------------------------------------------------------------------*/
617 * Poll IO register
619 * Poll register until (RegisterValue & DataMask) == Data
621 * @param[in] AccessWidth Access width
622 * @param[in] IoAddress IO address
623 * @param[in] Data Data to compare
624 * @param[in] DataMask And mask
625 * @param[in] Delay Poll for time in 100ns (not supported)
626 * @param[in] StdHeader Standard configuration header
629 VOID
630 LibAmdIoPoll (
631 IN ACCESS_WIDTH AccessWidth,
632 IN UINT16 IoAddress,
633 IN CONST VOID *Data,
634 IN CONST VOID *DataMask,
635 IN UINT64 Delay,
636 IN OUT AMD_CONFIG_PARAMS *StdHeader
639 UINT32 TempData;
640 UINT32 TempMask;
641 UINT32 Value;
642 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
643 do {
644 LibAmdIoRead (AccessWidth, IoAddress, &Value, NULL);
645 } while (TempData != (Value & TempMask));
648 /*---------------------------------------------------------------------------------------*/
650 * Read memory/MMIO
653 * @param[in] AccessWidth Access width
654 * @param[in] MemAddress Memory address
655 * @param[in] Value Pointer to data
656 * @param[in] StdHeader Standard configuration header
659 VOID
660 LibAmdMemRead (
661 IN ACCESS_WIDTH AccessWidth,
662 IN UINT64 MemAddress,
663 OUT VOID *Value,
664 IN OUT AMD_CONFIG_PARAMS *StdHeader
667 switch (AccessWidth) {
668 case AccessWidth8:
669 case AccessS3SaveWidth8:
670 *(UINT8 *) Value = Read64Mem8 (MemAddress);
671 break;
672 case AccessWidth16:
673 case AccessS3SaveWidth16:
674 *(UINT16 *) Value = Read64Mem16 (MemAddress);
675 break;
676 case AccessWidth32:
677 case AccessS3SaveWidth32:
678 *(UINT32 *) Value = Read64Mem32 (MemAddress);
679 break;
680 default:
681 ASSERT (FALSE);
682 break;
686 /*---------------------------------------------------------------------------------------*/
688 * Write memory/MMIO
691 * @param[in] AccessWidth Access width
692 * @param[in] MemAddress Memory address
693 * @param[in] Value Pointer to data
694 * @param[in] StdHeader Standard configuration header
697 VOID
698 LibAmdMemWrite (
699 IN ACCESS_WIDTH AccessWidth,
700 IN UINT64 MemAddress,
701 IN CONST VOID *Value,
702 IN OUT AMD_CONFIG_PARAMS *StdHeader
706 switch (AccessWidth) {
707 case AccessWidth8:
708 case AccessS3SaveWidth8:
709 Write64Mem8 (MemAddress, *((UINT8 *) Value));
710 break;
711 case AccessWidth16:
712 case AccessS3SaveWidth16:
713 Write64Mem16 (MemAddress, *((UINT16 *) Value));
714 break;
715 case AccessWidth32:
716 case AccessS3SaveWidth32:
717 Write64Mem32 (MemAddress, *((UINT32 *) Value));
718 break;
719 default:
720 ASSERT (FALSE);
721 break;
724 /*---------------------------------------------------------------------------------------*/
726 * Memory/MMIO read modify write
729 * @param[in] AccessWidth Access width
730 * @param[in] MemAddress Memory address
731 * @param[in] Data OR data
732 * @param[in] DataMask Mask to be used before data write back to register.
733 * @param[in] StdHeader Standard configuration header
736 VOID
737 LibAmdMemRMW (
738 IN ACCESS_WIDTH AccessWidth,
739 IN UINT64 MemAddress,
740 IN CONST VOID *Data,
741 IN CONST VOID *DataMask,
742 IN OUT AMD_CONFIG_PARAMS *StdHeader
745 UINT32 TempData;
746 UINT32 TempMask;
747 UINT32 Value;
748 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
749 LibAmdMemRead (AccessWidth, MemAddress, &Value, NULL);
750 Value = (Value & (~TempMask)) | TempData;
751 LibAmdMemWrite (AccessWidth, MemAddress, &Value, NULL);
754 /*---------------------------------------------------------------------------------------*/
756 * Poll Mmio
758 * Poll register until (RegisterValue & DataMask) == Data
760 * @param[in] AccessWidth Access width
761 * @param[in] MemAddress Memory address
762 * @param[in] Data Data to compare
763 * @param[in] DataMask AND mask
764 * @param[in] Delay Poll for time in 100ns (not supported)
765 * @param[in] StdHeader Standard configuration header
768 VOID
769 LibAmdMemPoll (
770 IN ACCESS_WIDTH AccessWidth,
771 IN UINT64 MemAddress,
772 IN CONST VOID *Data,
773 IN CONST VOID *DataMask,
774 IN UINT64 Delay,
775 IN OUT AMD_CONFIG_PARAMS *StdHeader
778 UINT32 TempData = 0;
779 UINT32 TempMask = 0;
780 UINT32 Value;
781 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
782 do {
783 LibAmdMemRead (AccessWidth, MemAddress, &Value, NULL);
784 } while (TempData != (Value & TempMask));
787 /*---------------------------------------------------------------------------------------*/
789 * Read PCI config space
792 * @param[in] AccessWidth Access width
793 * @param[in] PciAddress Pci address
794 * @param[in] Value Pointer to data
795 * @param[in] StdHeader Standard configuration header
798 VOID
799 LibAmdPciRead (
800 IN ACCESS_WIDTH AccessWidth,
801 IN PCI_ADDR PciAddress,
802 OUT VOID *Value,
803 IN OUT AMD_CONFIG_PARAMS *StdHeader
806 UINT32 LegacyPciAccess;
807 UINT32 MMIOSize;
808 UINT64 RMWrite;
809 UINT64 RMWritePrevious;
810 UINT64 MMIOAddress;
813 ASSERT (PciAddress.AddressValue != ILLEGAL_SBDFO);
814 if (!GetPciMmioAddress (&MMIOAddress, &MMIOSize, NULL)) {
815 // We need to convert our "portable" PCI address into a "real" PCI access
816 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)));
817 if (PciAddress.Address.Register <= 0xFF) {
818 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, NULL);
819 LibAmdIoRead (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, NULL);
820 } else {
821 LibAmdMsrRead (NB_CFG, &RMWritePrevious, NULL);
822 RMWrite = RMWritePrevious | 0x0000400000000000;
823 LibAmdMsrWrite (NB_CFG, &RMWrite, NULL);
824 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, NULL);
825 LibAmdIoRead (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, NULL);
826 LibAmdMsrWrite (NB_CFG, &RMWritePrevious, NULL);
828 //IDS_HDT_CONSOLE (LIB_PCI_RD, "~PCI RD %08x = %08x\n", LegacyPciAccess, *(UINT32 *)Value);
829 } else {
830 // Setup the MMIO address
831 ASSERT ((MMIOAddress + MMIOSize) > (MMIOAddress + (PciAddress.AddressValue & 0x0FFFFFFF)));
832 MMIOAddress += (PciAddress.AddressValue & 0x0FFFFFFF);
833 LibAmdMemRead (AccessWidth, MMIOAddress, Value, NULL);
834 //IDS_HDT_CONSOLE (LIB_PCI_RD, "~MMIO RD %08x = %08x\n", (UINT32) MMIOAddress, *(UINT32 *)Value);
838 /*---------------------------------------------------------------------------------------*/
840 * Write PCI config space
843 * @param[in] AccessWidth Access width
844 * @param[in] PciAddress Pci address
845 * @param[in] Value Pointer to data
846 * @param[in] StdHeader Standard configuration header
849 VOID
850 LibAmdPciWrite (
851 IN ACCESS_WIDTH AccessWidth,
852 IN PCI_ADDR PciAddress,
853 IN CONST VOID *Value,
854 IN OUT AMD_CONFIG_PARAMS *StdHeader
857 UINT32 LegacyPciAccess;
858 UINT32 MMIOSize;
859 UINT64 RMWrite;
860 UINT64 RMWritePrevious;
861 UINT64 MMIOAddress;
864 ASSERT (PciAddress.AddressValue != ILLEGAL_SBDFO);
865 if (!GetPciMmioAddress (&MMIOAddress, &MMIOSize, NULL)) {
866 // We need to convert our "portable" PCI address into a "real" PCI access
867 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)));
868 if (PciAddress.Address.Register <= 0xFF) {
869 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, NULL);
870 LibAmdIoWrite (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, NULL);
871 } else {
872 LibAmdMsrRead (NB_CFG, &RMWritePrevious, NULL);
873 RMWrite = RMWritePrevious | 0x0000400000000000;
874 LibAmdMsrWrite (NB_CFG, &RMWrite, NULL);
875 LibAmdIoWrite (AccessWidth32, IOCF8, &LegacyPciAccess, NULL);
876 LibAmdIoWrite (AccessWidth, IOCFC + (UINT16) (PciAddress.Address.Register & 0x3), Value, NULL);
877 LibAmdMsrWrite (NB_CFG, &RMWritePrevious, NULL);
879 //IDS_HDT_CONSOLE (LIB_PCI_WR, "~PCI WR %08x = %08x\n", LegacyPciAccess, *(UINT32 *)Value);
880 //printk(BIOS_DEBUG, "~PCI WR %08x = %08x\n", LegacyPciAccess, *(UINT32 *)Value);
881 //printk(BIOS_DEBUG, "LibAmdPciWrite\n");
882 } else {
883 // Setup the MMIO address
884 ASSERT ((MMIOAddress + MMIOSize) > (MMIOAddress + (PciAddress.AddressValue & 0x0FFFFFFF)));
885 MMIOAddress += (PciAddress.AddressValue & 0x0FFFFFFF);
886 LibAmdMemWrite (AccessWidth, MMIOAddress, Value, NULL);
887 //IDS_HDT_CONSOLE (LIB_PCI_WR, "~MMIO WR %08x = %08x\n", (UINT32) MMIOAddress, *(UINT32 *)Value);
888 //printk(BIOS_DEBUG, "~MMIO WR %08x = %08x\n", (UINT32) MMIOAddress, *(UINT32 *)Value);
889 //printk(BIOS_DEBUG, "LibAmdPciWrite mmio\n");
893 /*---------------------------------------------------------------------------------------*/
895 * PCI read modify write
898 * @param[in] AccessWidth Access width
899 * @param[in] PciAddress Pci address
900 * @param[in] Data OR Data
901 * @param[in] DataMask Mask to be used before data write back to register.
902 * @param[in] StdHeader Standard configuration header
905 VOID
906 LibAmdPciRMW (
907 IN ACCESS_WIDTH AccessWidth,
908 IN PCI_ADDR PciAddress,
909 IN CONST VOID *Data,
910 IN CONST VOID *DataMask,
911 IN OUT AMD_CONFIG_PARAMS *StdHeader
914 UINT32 TempData = 0;
915 UINT32 TempMask = 0;
916 UINT32 Value;
917 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
918 LibAmdPciRead (AccessWidth, PciAddress, &Value, NULL);
919 Value = (Value & (~TempMask)) | TempData;
920 LibAmdPciWrite (AccessWidth, PciAddress, &Value, NULL);
923 /*---------------------------------------------------------------------------------------*/
925 * Poll PCI config space register
927 * Poll register until (RegisterValue & DataMask) == Data
929 * @param[in] AccessWidth Access width
930 * @param[in] PciAddress Pci address
931 * @param[in] Data Data to compare
932 * @param[in] DataMask AND mask
933 * @param[in] Delay Poll for time in 100ns (not supported)
934 * @param[in] StdHeader Standard configuration header
937 VOID
938 LibAmdPciPoll (
939 IN ACCESS_WIDTH AccessWidth,
940 IN PCI_ADDR PciAddress,
941 IN CONST VOID *Data,
942 IN CONST VOID *DataMask,
943 IN UINT64 Delay,
944 IN OUT AMD_CONFIG_PARAMS *StdHeader
947 UINT32 TempData = 0;
948 UINT32 TempMask = 0;
949 UINT32 Value;
950 LibAmdGetDataFromPtr (AccessWidth, Data, DataMask, &TempData, &TempMask);
951 do {
952 LibAmdPciRead (AccessWidth, PciAddress, &Value, NULL);
953 } while (TempData != (Value & TempMask));
956 /*---------------------------------------------------------------------------------------*/
958 * Get MMIO base address for PCI accesses
960 * @param[out] MmioAddress PCI MMIO base address
961 * @param[out] MmioSize Size of region in bytes
962 * @param[in] StdHeader Standard configuration header
964 * @retval TRUE MmioAddress/MmioSize are valid
966 STATIC
967 BOOLEAN
968 GetPciMmioAddress (
969 OUT UINT64 *MmioAddress,
970 OUT UINT32 *MmioSize,
971 IN AMD_CONFIG_PARAMS *StdHeader
974 BOOLEAN MmioIsEnabled;
975 UINT32 EncodedSize;
976 UINT64 LocalMsrRegister;
978 MmioIsEnabled = FALSE;
979 LibAmdMsrRead (MSR_MMIO_Cfg_Base, &LocalMsrRegister, NULL);
980 if ((LocalMsrRegister & BIT0) != 0) {
981 *MmioAddress = LocalMsrRegister & 0xFFFFFFFFFFF00000;
982 EncodedSize = (UINT32) ((LocalMsrRegister & 0x3C) >> 2);
983 *MmioSize = ((1 << EncodedSize) * 0x100000);
984 MmioIsEnabled = TRUE;
986 return MmioIsEnabled;
989 /*---------------------------------------------------------------------------------------*/
991 * Read field of PCI config register.
995 * @param[in] Address Pci address (register must be DWORD aligned)
996 * @param[in] Highbit High bit position of the field in DWORD
997 * @param[in] Lowbit Low bit position of the field in DWORD
998 * @param[out] Value Pointer to data
999 * @param[in] StdHeader Standard configuration header
1001 VOID
1002 LibAmdPciReadBits (
1003 IN PCI_ADDR Address,
1004 IN UINT8 Highbit,
1005 IN UINT8 Lowbit,
1006 OUT UINT32 *Value,
1007 IN AMD_CONFIG_PARAMS *StdHeader
1010 ASSERT (Highbit < 32 && Lowbit < 32 && Highbit >= Lowbit && (Address.AddressValue & 3) == 0);
1012 LibAmdPciRead (AccessWidth32, Address, Value, NULL);
1013 *Value >>= Lowbit; // Shift
1015 // A 1 << 32 == 1 << 0 due to x86 SHL instruction, so skip if that is the case
1017 if ((Highbit - Lowbit) != 31) {
1018 *Value &= (((UINT32) 1 << (Highbit - Lowbit + 1)) - 1);
1022 /*---------------------------------------------------------------------------------------*/
1024 * Write field of PCI config register.
1028 * @param[in] Address Pci address (register must be DWORD aligned)
1029 * @param[in] Highbit High bit position of the field in DWORD
1030 * @param[in] Lowbit Low bit position of the field in DWORD
1031 * @param[in] Value Pointer to data
1032 * @param[in] StdHeader Standard configuration header
1034 VOID
1035 LibAmdPciWriteBits (
1036 IN PCI_ADDR Address,
1037 IN UINT8 Highbit,
1038 IN UINT8 Lowbit,
1039 IN CONST UINT32 *Value,
1040 IN AMD_CONFIG_PARAMS *StdHeader
1043 UINT32 Temp;
1044 UINT32 Mask;
1046 ASSERT (Highbit < 32 && Lowbit < 32 && Highbit >= Lowbit && (Address.AddressValue & 3) == 0);
1048 // A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case
1050 if ((Highbit - Lowbit) != 31) {
1051 Mask = (((UINT32) 1 << (Highbit - Lowbit + 1)) - 1);
1052 } else {
1053 Mask = (UINT32) 0xFFFFFFFF;
1056 LibAmdPciRead (AccessWidth32, Address, &Temp, NULL);
1057 Temp &= ~(Mask << Lowbit);
1058 Temp |= (*Value & Mask) << Lowbit;
1059 LibAmdPciWrite (AccessWidth32, Address, &Temp, NULL);
1062 /*---------------------------------------------------------------------------------------*/
1064 * Locate next capability pointer
1066 * Given a SBDFO this routine will find the next PCI capabilities list entry.
1067 * if the end of the list is reached, or if a problem is detected, then ILLEGAL_SBDFO is
1068 * returned.
1069 * To start a new search from the head of the list, specify a SBDFO with an offset of zero.
1071 * @param[in,out] Address Pci address
1072 * @param[in] StdHeader Standard configuration header
1075 VOID
1076 LibAmdPciFindNextCap (
1077 IN OUT PCI_ADDR *Address,
1078 IN AMD_CONFIG_PARAMS *StdHeader
1081 PCI_ADDR Base;
1082 UINT32 Offset;
1083 UINT32 Temp;
1084 PCI_ADDR TempAddress;
1086 ASSERT (Address != NULL);
1087 ASSERT (*(UINT32 *) Address != ILLEGAL_SBDFO);
1089 Base.AddressValue = Address->AddressValue;
1090 Offset = Base.Address.Register;
1091 Base.Address.Register = 0;
1093 Address->AddressValue = (UINT32) ILLEGAL_SBDFO;
1095 // Verify that the SBDFO points to a valid PCI device SANITY CHECK
1096 LibAmdPciRead (AccessWidth32, Base, &Temp, NULL);
1097 if (Temp == 0xFFFFFFFF) {
1098 ASSERT (FALSE);
1099 return; // There is no device at this address
1102 // Verify that the device supports a capability list
1103 TempAddress.AddressValue = Base.AddressValue + 0x04;
1104 LibAmdPciReadBits (TempAddress, 20, 20, &Temp, NULL);
1105 if (Temp == 0) {
1106 return; // This PCI device does not support capability lists
1109 if (Offset != 0) {
1110 // If we are continuing on an existing list
1111 TempAddress.AddressValue = Base.AddressValue + Offset;
1112 LibAmdPciReadBits (TempAddress, 15, 8, &Temp, NULL);
1113 } else {
1114 // We are starting on a new list
1115 TempAddress.AddressValue = Base.AddressValue + 0x34;
1116 LibAmdPciReadBits (TempAddress, 7, 0, &Temp, NULL);
1119 if (Temp == 0) {
1120 return; // We have reached the end of the capabilities list
1123 // Error detection and recovery- The statement below protects against
1124 // PCI devices with broken PCI capabilities lists. Detect a pointer
1125 // that is not uint32 aligned, points into the first 64 reserved DWORDs
1126 // or points back to itself.
1127 if (((Temp & 3) != 0) || (Temp == Offset) || (Temp < 0x40)) {
1128 ASSERT (FALSE);
1129 return;
1132 Address->AddressValue = Base.AddressValue + Temp;
1133 return;
1136 /*---------------------------------------------------------------------------------------*/
1138 * Set memory with value
1141 * @param[in,out] Destination Pointer to memory range
1142 * @param[in] Value Value to set memory with
1143 * @param[in] FillLength Size of the memory range
1144 * @param[in] StdHeader Standard configuration header (Optional)
1146 VOID
1147 LibAmdMemFill (
1148 IN VOID *Destination,
1149 IN UINT8 Value,
1150 IN UINTN FillLength,
1151 IN OUT AMD_CONFIG_PARAMS *StdHeader
1154 UINT8 *Dest;
1155 Dest = Destination;
1156 while ((FillLength--) != 0) {
1157 *Dest++ = Value;
1161 /*---------------------------------------------------------------------------------------*/
1163 * Copy memory
1166 * @param[in,out] Destination Pointer to destination buffer
1167 * @param[in] Source Pointer to source buffer
1168 * @param[in] CopyLength buffer length
1169 * @param[in] StdHeader Standard configuration header (Optional)
1171 VOID
1172 LibAmdMemCopy (
1173 IN VOID *Destination,
1174 IN CONST VOID *Source,
1175 IN UINTN CopyLength,
1176 IN OUT AMD_CONFIG_PARAMS *StdHeader
1179 UINT8 *Dest;
1180 CONST UINT8 *SourcePtr;
1181 Dest = Destination;
1182 SourcePtr = Source;
1183 while ((CopyLength--) != 0) {
1184 *Dest++ = *SourcePtr++;
1188 /*---------------------------------------------------------------------------------------*/
1190 * Verify checksum of binary image (B1/B2/B3)
1193 * @param[in] ImagePtr Pointer to image start
1194 * @retval TRUE Checksum valid
1195 * @retval FALSE Checksum invalid
1197 BOOLEAN
1198 LibAmdVerifyImageChecksum (
1199 IN CONST VOID *ImagePtr
1202 // Assume ImagePtr points to the binary start ($AMD)
1203 // Checksum is on an even boundary in AMD_IMAGE_HEADER
1205 UINT16 Sum;
1206 UINT32 i;
1208 Sum = 0;
1210 i = ((AMD_IMAGE_HEADER*) ImagePtr)->ImageSize;
1212 while (i > 1) {
1213 Sum = Sum + *((UINT16 *)ImagePtr);
1214 ImagePtr = (VOID *) ((UINT8 *)ImagePtr + 2);
1215 i = i - 2;
1217 if (i > 0) {
1218 Sum = Sum + *((UINT8 *) ImagePtr);
1221 return (Sum == 0)?TRUE:FALSE;
1224 /*---------------------------------------------------------------------------------------*/
1226 * Locate AMD binary image that contain specific module
1229 * @param[in] StartAddress Pointer to start range
1230 * @param[in] EndAddress Pointer to end range
1231 * @param[in] Alignment Image address alignment
1232 * @param[in] ModuleSignature Module signature.
1233 * @retval NULL if image not found
1234 * @retval pointer to image header
1236 CONST VOID *
1237 LibAmdLocateImage (
1238 IN CONST VOID *StartAddress,
1239 IN CONST VOID *EndAddress,
1240 IN UINT32 Alignment,
1241 IN CONST CHAR8 ModuleSignature[8]
1245 CONST UINT8 *CurrentPtr = StartAddress;
1246 AMD_MODULE_HEADER *ModuleHeaderPtr;
1247 CONST UINT64 SearchStr = *((UINT64*)ModuleSignature);
1249 // Search from start to end incrementing by alignment
1250 while ((CurrentPtr >= (UINT8 *) StartAddress) && (CurrentPtr < (UINT8 *) EndAddress)) {
1251 // First find a binary image
1252 if (IMAGE_SIGNATURE == *((UINT32 *) CurrentPtr)) {
1253 // TODO Figure out a way to fix the AGESA binary checksum
1254 // if (LibAmdVerifyImageChecksum (CurrentPtr)) {
1255 // If we have a valid image, search module linked list for a match
1256 ModuleHeaderPtr = (AMD_MODULE_HEADER*)(((AMD_IMAGE_HEADER *) CurrentPtr)->ModuleInfoOffset);
1257 while ((ModuleHeaderPtr != NULL) &&
1258 (MODULE_SIGNATURE == *((UINT32*)&(ModuleHeaderPtr->ModuleHeaderSignature)))) {
1259 if (SearchStr == *((UINT64*)&(ModuleHeaderPtr->ModuleIdentifier))) {
1260 return CurrentPtr;
1262 ModuleHeaderPtr = (AMD_MODULE_HEADER *)ModuleHeaderPtr->NextBlock;
1264 // }
1266 CurrentPtr += Alignment;
1268 return NULL;
1271 /*---------------------------------------------------------------------------------------*/
1273 * Returns the package type mask for the processor
1276 * @param[in] StdHeader Standard configuration header (Optional)
1279 // Returns the package type mask for the processor
1280 UINT32
1281 LibAmdGetPackageType (
1282 IN AMD_CONFIG_PARAMS *StdHeader
1285 UINT32 ProcessorPackageType;
1286 CPUID_DATA CpuId;
1288 LibAmdCpuidRead (0x80000001, &CpuId, NULL);
1289 ProcessorPackageType = (UINT32) (CpuId.EBX_Reg >> 28) & 0xF; // bit 31:28
1290 return (UINT32) (1 << ProcessorPackageType);
1293 /*---------------------------------------------------------------------------------------*/
1295 * Returns the package type mask for the processor
1298 * @param[in] AccessWidth Access width
1299 * @param[in] Data data
1300 * @param[in] DataMask data
1301 * @param[out] TemData typecast data
1302 * @param[out] TempDataMask typecast data
1305 STATIC
1306 VOID
1307 LibAmdGetDataFromPtr (
1308 IN ACCESS_WIDTH AccessWidth,
1309 IN CONST VOID *Data,
1310 IN CONST VOID *DataMask,
1311 OUT UINT32 *TemData,
1312 OUT UINT32 *TempDataMask
1315 switch (AccessWidth) {
1316 case AccessWidth8:
1317 case AccessS3SaveWidth8:
1318 *TemData = (UINT32)*(UINT8 *) Data;
1319 *TempDataMask = (UINT32)*(UINT8 *) DataMask;
1320 break;
1321 case AccessWidth16:
1322 case AccessS3SaveWidth16:
1323 *TemData = (UINT32)*(UINT16 *) Data;
1324 *TempDataMask = (UINT32)*(UINT16 *) DataMask;
1325 break;
1326 case AccessWidth32:
1327 case AccessS3SaveWidth32:
1328 *TemData = *(UINT32 *) Data;
1329 *TempDataMask = *(UINT32 *) DataMask;
1330 break;
1331 default:
1332 IDS_ERROR_TRAP;
1333 break;
1337 /*---------------------------------------------------------------------------------------*/
1339 * Returns the package type mask for the processor
1342 * @param[in] AccessWidth Access width
1343 * @retval Width in number of bytes
1346 UINT8
1347 LibAmdAccessWidth (
1348 IN ACCESS_WIDTH AccessWidth
1351 UINT8 Width;
1353 switch (AccessWidth) {
1354 case AccessWidth8:
1355 case AccessS3SaveWidth8:
1356 Width = 1;
1357 break;
1358 case AccessWidth16:
1359 case AccessS3SaveWidth16:
1360 Width = 2;
1361 break;
1362 case AccessWidth32:
1363 case AccessS3SaveWidth32:
1364 Width = 4;
1365 break;
1366 case AccessWidth64:
1367 case AccessS3SaveWidth64:
1368 Width = 8;
1369 break;
1370 default:
1371 Width = 0;
1372 IDS_ERROR_TRAP;
1373 break;
1375 return Width;
1378 AMDLIB_OPTIMIZE
1379 VOID
1380 CpuidRead (
1381 IN UINT32 CpuidFcnAddress,
1382 OUT CPUID_DATA *Value
1385 __cpuid ((int *)Value, CpuidFcnAddress);
1388 AMDLIB_OPTIMIZE
1389 UINT8
1390 ReadNumberOfCpuCores(
1391 void
1394 CPUID_DATA Value;
1395 CpuidRead (0x80000008, &Value);
1396 return Value.ECX_Reg & 0xff;
1399 BOOLEAN
1400 IdsErrorStop (
1401 IN UINT32 FileCode
1404 struct POST {
1405 UINT16 deadlo;
1406 UINT32 messagelo;
1407 UINT16 deadhi;
1408 UINT32 messagehi;
1409 } post = {0xDEAD, FileCode, 0xDEAD, FileCode};
1410 UINT16 offset = 0;
1411 UINT16 j;
1413 while(1) {
1414 offset %= sizeof(struct POST) / 2;
1415 WriteIo16(80, *((UINT16 *)&post)+offset);
1416 ++offset;
1417 for (j=0; j<250; ++j) {
1418 ReadIo8(80);