aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/pi/00670F00/Proc/CPU/Table.h
blob: 3742c19059f01b1c0c6a4b5a25b8a8156b3233a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
/* $NoKeywords:$ */
/**
 * @file
 *
 * AMD CPU Register Table Related Functions
 *
 * Contains code to initialize the CPU MSRs and PCI registers with BKDG recommended values
 *
 * @xrefitem bom "File Content Label" "Release Content"
 * @e project:      AGESA
 * @e sub-project:  CPU
 * @e \$Revision$   @e \$Date$
 *
 */
 /*****************************************************************************
 *
 * Copyright (c) 2008 - 2017, Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ***************************************************************************/

#include <check_for_wrapper.h>

#ifndef _CPU_TABLE_H_
#define _CPU_TABLE_H_


/**
 * @page regtableimpl Register Table Implementation Guide
 *
 * This register table implementation is modular and extensible, so that support code as
 * well as table data can be family specific or built out if not needed, and new types
 * of table entries can be added with low overhead.  Because many aspects are now generic,
 * there can be common implementations for CPU revision and platform feature matching and for
 * finding and iterating tables.
 *
 * @par Adding a new table entry type.
 *
 * To add a new table entry type follow these steps.
 * <ul>
 * <li>  Add a member to the enum TABLE_ENTRY_TYPE which is a descriptive name of the entry's purpose
 *       or distinct characteristics.
 *
 * <li>  Create an entry data struct with the customized data needed.  For example, custom register designations,
 *       data and mask sizes, or feature comparisons.  Name your struct by adding "_" and upper-casing the enum name
 *       and adding "_TYPE_ENTRY_DATA" at the end.
 *
 * <li>  Add the entry data type as a member of the TABLE_ENTRY_DATA union.  Be aware of the size of your
 *       entry data struct; all table entries in all tables will share any size increase you introduce!
 *
 * <li>  If your data entry contains any member types except for UINT32, you can't use the generic first union member
 *       for the initializers that make up the actual tables (it's just UINT32's). The generic MSR entry is
 *       an example. Follow the steps below:
 *
 *       <ul>
 *       <li>  Make a union which has your entry data type as the first member.  Use TABLE_ENTRY_DATA as the
 *             second member.  Name this with your register followed by "_DATA_INITIALIZER".
 *
 *       <li>  Make a copy of TABLE_ENTRY_FIELDS, and rename it your register "_TYPE_ENTRY_INITIALIZER".  Rename
 *             the TABLE_ENTRY_DATA member of that struct to have the type you created in the previous step.
 *             This type can be used to declare an array of entries and make a register table in some family specific
 *             file.
 *       </ul>
 *
 * <li>  Add the descriptor that will link table entries of your data type to an implementation for it.
 *       <ul>
 *       <li>  Find the options file which instantiates the CPU_SPECIFIC_SERVICES for each logical model that will
 *             support the new entry type.
 *
 *       <li> From there find the instantiation of its TABLE_ENTRY_TYPE_DESCRIPTOR.  Add a descriptor to the
 *            to the list for your new type.  Provide the name of a function which will implement the
 *            entry data.  The function name should reflect that it implements the action for the entry type.
 *            The function must be an instance of F_DO_TABLE_ENTRY.
 *       </ul>
 *
 * <li>  Implement the function for your entry type data.  (If parts of it are family specific add methods to
 *       CPU_SPECIFIC_SERVICES for that and implement them for each family or model required.)  @n
 *       The definition of the function must conform to F_DO_TABLE_ENTRY.
 *       In the function preamble, include a cross reference to the entry enum:
 *       @code
 *       *
 *       * @TableEntryTypeMethod{::MyRegister}
 *       *
 *       @endcode
 *
 * </ul>
 *
 * @par  Adding a new Register Table
 *
 * To add a new register table for a logical CPU model follow the steps below.
 *
 * <ul>
 * <li>  Find the options file which instantiates the CPU_SPECIFIC_SERVICES for the logical model that
 *       should include the table.
 *
 * <li>  From there find the instantiation of its REGISTER_TABLE list. Add the name of the new register table.
 * </ul>
 *
 */

/*------------------------------------------------------------------------------------------*/
/*
 * Define the supported table entries.
 */
/*------------------------------------------------------------------------------------------*/

/**
 * These are the available types of table entries.
 *
 * Each type corresponds to:
 * - a semantics for the type specific data, for example semantics for a Register value,
 * Data value, and Mask value.
 * - optionally, including a method for type specific matching criteria
 * - a method for writing the desired update to the hardware.
 *
 * All types share in common a method to match CPU Family and Model and a method to match
 * platform feature set.
 *
 * N O T E: We use UINT16 for storing table entry type
 */
typedef enum {
  MsrRegister,                 ///< Processor MSR registers.
  PciRegister,                 ///< Processor Config Space registers.
  FamSpecificWorkaround,       ///< Processor Family Specific Workarounds which are @b not practical using the other types.
  ProfileFixup,                ///< Processor Performance Profile fixups to PCI Config Registers.
  CoreCountsPciRegister,       ///< Processor PCI Config Registers which depend on core counts.
  CompUnitCountsPciRegister,   ///< Processor PCI Config Registers which depend on compute unit counts.
  CompUnitCountsMsr,           ///< Processor MSRs which depend on compute unit counts.
  CpuRevPciRegister,           ///< Processor PCI Config Registers which depend on family / revision.
  CpuRevMsr,                   ///< Processor MSR which depend on family / revision.
  CpuRevFamSpecificWorkaround, ///< Processor Family Specific Workarounds which depend on family / revision.
  SmuIndexReg,                 ///< SMU index data registers.
  ProfileFixupSmuIndexReg,     ///< Performance Profile fixups to SMU index data registers.
  CopyBitField,                ///< Copy bitfield from register A to register B
  TableEntryTypeMax,           ///< Not a valid entry type, use for limit checking.
  TableTerminator = 0xFFFF     ///< A signature to indicate end to Jam table.
} TABLE_ENTRY_TYPE;

/*------------------------------------------------------------------------------------------*/
/*
 * Useful types and defines: Selectors, Platform Features, and type specific features.
 */
/*------------------------------------------------------------------------------------------*/

/**
 * Select tables for the current core.
 *
 * This allows more efficient register table processing, by allowing cores to skip
 * redundantly setting PCI registers, for example.  This feature is not intended to
 * be relied on for function:  it is valid to have a single register table with all settings
 * processed by every core; it's just slower.
 *
 */
typedef enum {
  AllCores,                   ///< Select only tables which apply to all cores.
  ComputeUnitPrimary,         ///< Select tables which apply to the primary core of a compute unit (SharedC, SharedNc).
  PrimaryCores,               ///< Select tables which apply to primary cores.
  BscCore,                    ///< Select tables which apply to the boot core.
  TableCoreSelectorMax        ///< Not a valid selector, use for limit checking.
} TABLE_CORE_SELECTOR;

/**
 * Possible time points at which register tables can be processed.
 *
 */
typedef enum {
  AmdRegisterTableTpBeforeApLaunch,     ///< Cpu code just prior to launching APs.
  AmdRegisterTableTpAfterApLaunch,      ///< Cpu code just after all APs have been launched.
  AmdRegisterTableTpBeforeApLaunchSecureS3, ///< Cpu code just prior to launching APs for secure S3
  AmdRegisterTableTpAfterApLaunchSecureS3, ///< Cpu code just after all APs have been launched for secure S3
  MaxAmdRegisterTableTps                ///< Not a valid time point, use for limit checking.
} REGISTER_TABLE_TIME_POINT;

//----------------------------------------------------------------------------
//                         CPU PERFORM EARLY INIT ON CORE
//
//----------------------------------------------------------------------------
/// Flag definition.

// Condition
#define PERFORM_EARLY_WARM_RESET    0x1          // bit  0 --- the related function needs to be run if it's warm reset
#define PERFORM_EARLY_COLD_BOOT     0x2          // bit  1 --- the related function needs to be run if it's cold boot

#define PERFORM_EARLY_ANY_CONDITION (PERFORM_EARLY_WARM_RESET | PERFORM_EARLY_COLD_BOOT)

// Initializer bit pattern values for platform features.
// Keep in synch with the PLATFORM_FEATURES struct!

// The 5 control flow modes.
#define AMD_PF_NFCM           BIT0
#define AMD_PF_UMA            BIT1    // UMA_DR
#define AMD_PF_UMA_IFCM       BIT2
#define AMD_PF_IFCM           BIT3
#define AMD_PF_IOMMU          BIT4
// Degree of HT connectivity possible.
#define AMD_PF_SINGLE_LINK    BIT5
#define AMD_PF_MULTI_LINK     BIT6
// For some legacy MSRs, define a couple core count bits.  Do not continue adding
// core counts to the platform feats, if you need more than this design a table entry type.
// Here, provide exactly 1, exactly 2, or anything else.
#define AMD_PF_SINGLE_CORE    BIT7
#define AMD_PF_DUAL_CORE      BIT8
#define AMD_PF_MULTI_CORE     BIT9

// Not a platform type, but treat all others as AND
#define AMD_PF_AND            BIT31

#define AMD_PF_ALL    (AMD_PF_NFCM          | \
                       AMD_PF_UMA           | \
                       AMD_PF_UMA_IFCM      | \
                       AMD_PF_IFCM          | \
                       AMD_PF_IOMMU         | \
                       AMD_PF_SINGLE_LINK   | \
                       AMD_PF_MULTI_LINK    | \
                       AMD_PF_SINGLE_CORE   | \
                       AMD_PF_DUAL_CORE     | \
                       AMD_PF_MULTI_CORE)
// Do not include AMD_PF_AND in AMD_PF_ALL !

/**
 * The current platform features.
 *
 * Keep this in sync with defines above that are used in the initializers!
 *
 * The comments with the bit number are useful for the computing the reserved member size, but
 * do not write code that assumes you know what bit number one of these members is.
 *
 * These platform features are standard for all logical families and models.
 */
typedef struct {
  UINT32          PlatformNfcm:1;             ///< BIT_0 Normal Flow Control Mode.
  UINT32          PlatformUma:1;              ///< BIT_1 UMA (Display Refresh) Flow Control.
  UINT32          PlatformUmaIfcm:1;          ///< BIT_2 UMA using Isochronous Flow Control.
  UINT32          PlatformIfcm:1;             ///< BIT_3 Isochronous Flow Control Mode (not UMA).
  UINT32          PlatformIommu:1;            ///< BIT_4 IOMMU (a special case Isochronous mode).
  UINT32          PlatformSingleLink:1;       ///< BIT_5 The processor is in a package which implements only a single HT Link.
  UINT32          PlatformMultiLink:1;        ///< BIT_6 The processor is in a package which implements more than one HT Link.
  UINT32          PlatformSingleCore:1;       ///< BIT_7 Single Core processor, for legacy entries.
  UINT32          PlatformDualCore:1;         ///< BIT_8 Dual Core processor, for legacy entries.
  UINT32          PlatformMultiCore:1;        ///< BIT_9 More than dual Core processor, for legacy entries.
  UINT32          :(30 - 9);                  ///< The possibilities are (not quite) endless.
  UINT32          AndPlatformFeats:1;         ///< BIT_31
} PLATFORM_FEATURES;

/**
 * Platform Features
 */
typedef union {
  UINT32            PlatformValue;            ///< Describe Platform Features in UINT32.
  ///< This one goes first, because then initializers use it automatically for the union.
  PLATFORM_FEATURES PlatformFeatures;         ///< Describe Platform Features in structure
} PLATFORM_FEATS;

// Initializer bit patterns for PERFORMANCE_PROFILE_FEATS.
#define PERFORMANCE_REFRESH_REQUEST_32B       BIT0
#define PERFORMANCE_L3_CACHE                  BIT1
#define PERFORMANCE_NO_L3_CACHE               BIT2
#define PERFORMANCE_MCT_ISOC_VARIABLE         BIT3
#define PERFORMANCE_IS_WARM_RESET             BIT4
#define PERFORMANCE_VRM_HIGH_SPEED_ENABLE     BIT5
#define PERFORMANCE_NB_PSTATES_ENABLE         BIT6
#define PERFORMANCE_AND                       BIT31

#define PERFORMANCE_PROFILE_ALL   (PERFORMANCE_REFRESH_REQUEST_32B | \
                                   PERFORMANCE_L3_CACHE            | \
                                   PERFORMANCE_NO_L3_CACHE         | \
                                   PERFORMANCE_MCT_ISOC_VARIABLE   | \
                                   PERFORMANCE_IS_WARM_RESET       | \
                                   PERFORMANCE_VRM_HIGH_SPEED_ENABLE | \
                                   PERFORMANCE_NB_PSTATES_ENABLE)

/**
 * Performance Profile specific Type Features.
 *
 * Register settings for the different control flow modes can have additional dependencies
 */
typedef struct {
  UINT32       RefreshRequest32Byte:1;         ///< BIT_0.   Display Refresh Requests use 32 bytes (32BE).
  UINT32       L3Cache:1;                      ///< BIT_1    L3 Cache is present.
  UINT32       NoL3Cache:1;                    ///< BIT_2    L3 Cache is NOT present.
  UINT32       MctIsocVariable:1;              ///< BIT_3    Mct Isoc Read Priority set to variable.
  UINT32       IsWarmReset:1;                  ///< BIT_4    This boot is on a warm reset, cold reset pass is already completed.
  UINT32       VrmHighSpeed:1;                 ///< BIT_5    Select high speed VRM.
  UINT32       NbPstates:1;                    ///< BIT_6    Northbridge PStates are enabled
  UINT32       :(30 - 6);                      ///< available for future expansion.
  UINT32       AndPerformanceFeats:1;          ///< BIT_31.  AND other selected features.
} PERFORMANCE_PROFILE_FEATURES;

/**
 * Performance Profile features.
 */
typedef union {
  UINT32                        PerformanceProfileValue;     ///< Initializer value.
  PERFORMANCE_PROFILE_FEATURES  PerformanceProfileFeatures;  ///< The performance profile features.
} PERFORMANCE_PROFILE_FEATS;

// Initializer Values for Package Type
#define PACKAGE_TYPE_ALL              0xFFFF       ///< Package Type apply all packages

// Core Range Initializer values.
#define COUNT_RANGE_LOW            0ul
#define COUNT_RANGE_HIGH           0xFFul

// A count range matching none is often useful as the second range, matching will then be
// based on the first range.  A count range all is provided as a first range for default settings.
#define COUNT_RANGE_NONE           ((((COUNT_RANGE_HIGH) << 8) | (COUNT_RANGE_HIGH)) << 16)
#define COUNT_RANGE_ALL            (((COUNT_RANGE_HIGH) << 8) | (COUNT_RANGE_LOW))
#define IGNORE_FREQ_0              (((COUNT_RANGE_HIGH) << 8) | (COUNT_RANGE_HIGH))
#define IGNORE_PROCESSOR_0         (((COUNT_RANGE_HIGH) << 8) | (COUNT_RANGE_HIGH))

#define CORE_RANGE_0(min, max)            ((((UINT32)(max)) << 8) | (UINT32)(min))
#define CORE_RANGE_1(min, max)            (((((UINT32)(max)) << 8) | (UINT32)(min)) << 16)
#define PROCESSOR_RANGE_0(min, max)       ((((UINT32)(max)) << 8) | (UINT32)(min))
#define PROCESSOR_RANGE_1(min, max)       (((((UINT32)(max)) << 8) | (UINT32)(min)) << 16)
#define DEGREE_RANGE_0(min, max)          ((((UINT32)(max)) << 8) | (UINT32)(min))
#define DEGREE_RANGE_1(min, max)          (((((UINT32)(max)) << 8) | (UINT32)(min)) << 16)
#define FREQ_RANGE_0(min, max)            ((((UINT32)(max)) << 8) | (UINT32)(min))
#define FREQ_RANGE_1(min, max)            (((((UINT32)(max)) << 8) | (UINT32)(min)) << 16)
#define COMPUTE_UNIT_RANGE_0(min, max)    ((((UINT32)(max)) << 8) | (UINT32)(min))
#define COMPUTE_UNIT_RANGE_1(min, max)    (((((UINT32)(max)) << 8) | (UINT32)(min)) << 16)

/**
 * Count Range Feature, two count ranges for core counts, processor counts, or node counts.
 */
typedef struct {
  UINT32       Range0Min:8;           ///< The minimum of the first count range.
  UINT32       Range0Max:8;           ///< The maximum of the first count range.
  UINT32       Range1Min:8;           ///< The minimum of the second count range.
  UINT32       Range1Max:8;           ///< The maximum of the second count range.
} COUNT_RANGE_FEATURE;

/**
 * Core Count Ranges for table data.
 *
 * Provide a pair of core count ranges. If the actual core count is included in either range (OR),
 * the feature should be considered a match.
 */
typedef union {
  UINT32       CoreRangeValue;          ///< Initializer value.
  COUNT_RANGE_FEATURE CoreRanges;       ///< The Core Counts.
} CORE_COUNT_RANGES;

/**
 * Compute unit count ranges for table data.
 *
 * Provide a pair of compute unit count ranges. If the actual counts are included in either ranges (OR),
 * the feature should be considered a match.
 */
typedef union {
  UINT32    ComputeUnitRangeValue;                ///< Initializer value.
  COUNT_RANGE_FEATURE ComputeUnitRanges;          ///< The Processor and Node Counts.
} COMPUTE_UNIT_COUNTS;

/*------------------------------------------------------------------------------------------*/
/*
 * The specific data for each table entry.
 */
/*------------------------------------------------------------------------------------------*/
#define BSU8(u8)      ((UINT8) (u8)  & 0xFF)
#define BSU16(u16)    ((UINT16) (u16) & 0xFF), (((UINT16) (u16) >> 8) & 0xFF)
#define BSU32(u32)    ((UINT32) (u32) & 0xFF), (((UINT32) (u32) >> 8) & 0xFF), (((UINT32) (u32) >> 16) & 0xFF), (((UINT32) (u32) >> 24) & 0xFF)
#define BSU64(u64)    ((UINT64) (u64) & 0xFF), (((UINT64) (u64) >> 8) & 0xFF), (((UINT64) (u64) >> 16) & 0xFF), (((UINT64) (u64) >> 24) & 0xFF), \
                      (((UINT64) (u64) >> 32) & 0xFF), (((UINT64) (u64) >> 40) & 0xFF), (((UINT64) (u64) >> 48) & 0xFF), (((UINT64) (u64) >> 56) & 0xFF)

#define MAKE_ENTRY_TYPE(Type)                      BSU16 (Type)
#define MAKE_PERFORMANCE_PROFILE_FEATS(TypeFeats)  BSU32 (TypeFeats)
#define MAKE_CORE_COUNT_RANGES(CoreCounts)         BSU32 (CoreCounts)
#define MAKE_COMPUTE_UNIT_COUNTS(CUCounts)         BSU32 (CUCounts)
#define MAKE_CPU_LOGICAL_ID(Family, Revision)      BSU16 (Family), BSU16 (Revision)
#define MAKE_TABLE_TERMINATOR BSU16 (TableTerminator)

#define NUMBER_OF_TABLE_ENTRIES(Table) ((sizeof (Table) / sizeof (Table[0])) - 1)

/**
 * Table Entry Data for MSR Registers.
 *
 * Apply data to register after mask, for MSRs.
 */
typedef struct {
  UINT32  Address;                    ///< MSR address
  UINT64  Data;                       ///< Data to set in the MSR
  UINT64  Mask;                       ///< Mask to be applied to the MSR. Set every bit of all updated fields.
} MSR_TYPE_ENTRY_DATA;
#define MAKE_MSR_DATA(Address, Data, Mask) BSU32 (Address), BSU64 (Data), BSU64 (Mask)
#define MAKE_MSR_ENTRY(Address, Data, Mask) MAKE_ENTRY_TYPE (MsrRegister), MAKE_MSR_DATA(Address, Data, Mask)

/**
 * Table Entry Data for PCI Registers.
 *
 * Apply data to register after mask, for PCI Config registers.
 */
typedef struct {
  PCI_ADDR  Address;                  ///< Address should contain Function, Offset only.  It will apply to all CPUs
  UINT32    Data;                     ///< Data to be written into PCI device
  UINT32    Mask;                     ///< Mask to be used before data write. Set every bit of all updated fields.
} PCI_TYPE_ENTRY_DATA;
#define MAKE_PCI_DATA(Address, Data, Mask) BSU32 (Address), BSU32 (Data), BSU32 (Mask)
#define MAKE_PCI_ENTRY(Address, Data, Mask) MAKE_ENTRY_TYPE (PciRegister), MAKE_PCI_DATA(Address, Data, Mask)

/**
 * Table Entry Data for Profile Fixup Registers.
 *
 * If TypeFeats matches current config, apply data to register after mask for PCI Config registers.
 */
typedef struct {
  PERFORMANCE_PROFILE_FEATS TypeFeats; ///< Profile Fixup Features.
  PCI_TYPE_ENTRY_DATA PciEntry;        ///< The PCI Register entry data.
} PROFILE_FIXUP_TYPE_ENTRY_DATA;
#define MAKE_PROFILE_FIXUP_ENTRY(TypeFeats, Address, Data, Mask) MAKE_ENTRY_TYPE (ProfileFixup), MAKE_PERFORMANCE_PROFILE_FEATS (TypeFeats), MAKE_PCI_DATA (Address, Data, Mask)

/**
 * Core Count dependent PCI registers.
 *
 */
typedef struct {
  PERFORMANCE_PROFILE_FEATS TypeFeats; ///< Profile Fixup Features.
  CORE_COUNT_RANGES CoreCounts;        ///< Specify up to two core count ranges to match.
  PCI_TYPE_ENTRY_DATA PciEntry;        ///< The PCI Register entry data.
} CORE_COUNTS_PCI_TYPE_ENTRY_DATA;
#define MAKE_CORE_COUNTS_PCI_ENTRY(TypeFeats, CoreCounts, Address, Data, Mask) MAKE_ENTRY_TYPE (CoreCountsPciRegister), MAKE_PERFORMANCE_PROFILE_FEATS (TypeFeats), MAKE_CORE_COUNT_RANGES (CoreCounts), MAKE_PCI_DATA (Address, Data, Mask)

/**
 * Compute Unit Count dependent PCI registers.
 *
 */
typedef struct {
  PERFORMANCE_PROFILE_FEATS TypeFeats;         ///< Profile Fixup Features.
  COMPUTE_UNIT_COUNTS       ComputeUnitCounts; ///< Specify a compute unit count range.
  PCI_TYPE_ENTRY_DATA       PciEntry;          ///< The PCI Register entry data.
} COMPUTE_UNIT_COUNTS_PCI_TYPE_ENTRY_DATA;
#define MAKE_COMPUTE_UNIT_COUNTS_PCI_ENTRY(TypeFeats, CUCounts, Address, Data, Mask) MAKE_ENTRY_TYPE (CompUnitCountsPciRegister), MAKE_PERFORMANCE_PROFILE_FEATS (TypeFeats), MAKE_COMPUTE_UNIT_COUNTS (CUCounts), MAKE_PCI_DATA (Address, Data, Mask)

/**
 * Compute Unit Count dependent MSR registers.
 *
 */
typedef struct {
  COMPUTE_UNIT_COUNTS       ComputeUnitCounts; ///< Specify a compute unit count range.
  MSR_TYPE_ENTRY_DATA       MsrEntry;          ///< The MSR Register entry data.
} COMPUTE_UNIT_COUNTS_MSR_TYPE_ENTRY_DATA;
#define MAKE_COMPUTE_UNIT_COUNTS_MSR_ENTRY(CUCounts, Address, Data, Mask) MAKE_ENTRY_TYPE (CompUnitCountsMsr), MAKE_COMPUTE_UNIT_COUNTS (CUCounts), MAKE_MSR_DATA (Address, Data, Mask)


/**
 * A Family Specific Workaround method.
 *
 * \@TableTypeFamSpecificInstances.
 *
 * When called, the entry's CPU Logical ID and Platform Features matched the current config.
 * The method must implement any specific criteria checking for the workaround.
 *
 * See if you can use the other entries or make an entry specifically for the fix.
 * After all, the purpose of having a table entry is to @b NOT have code which
 * isn't generic feature code, but is family/model specific.
 *
 * @param[in]     Data       The table data value, for example to indicate which CPU and Platform types matched.
 * @param[in]     StdHeader  Config params for library, services.
 */
typedef VOID F_FAM_SPECIFIC_WORKAROUND (
  IN       UINT32              Data,
  IN       AMD_CONFIG_PARAMS   *StdHeader
  );
/// Reference to a method.
typedef F_FAM_SPECIFIC_WORKAROUND *PF_FAM_SPECIFIC_WORKAROUND;

/**
 * Table Entry Data for Family Specific Workarounds.
 *
 * See if you can use the other entries or make an entry specifically for the fix.
 * After all, the purpose of having a table entry is to @b NOT have code which
 * isn't generic feature code, but is family/model specific.
 *
 * Call DoAction passing Data.
 */
typedef struct {
  UINT32    FunctionIndex;            ///< A function implementing the workaround.
  UINT32    Data;                     ///< This data is passed to DoAction().
} FAM_SPECIFIC_WORKAROUND_TYPE_ENTRY_DATA;
#define MAKE_FAM_SPECIFIC_WORKAROUND_DATA(FunctionIndex, Data) BSU32 (FunctionIndex), BSU32 (Data)
#define MAKE_FAM_SPECIFIC_WORKAROUND_ENTRY(FunctionIndex, Data) MAKE_ENTRY_TYPE (FamSpecificWorkaround), MAKE_FAM_SPECIFIC_WORKAROUND_DATA(FunctionIndex, Data)

/**
 * Table Entry Data for CPU revision specific PCI Registers.
 *
 * Apply data to register after mask, for PCI Config registers.
 */
typedef struct {
  CPU_LOGICAL_ID  CpuRevision;        ///< Common CPU Logical ID match criteria.
  PCI_ADDR        Address;            ///< Address should contain Function, Offset only.  It will apply to all CPUs
  UINT32          Data;               ///< Data to be written into PCI device
  UINT32          Mask;               ///< Mask to be used before data write. Set every bit of all updated fields.
} CPU_REV_PCI_TYPE_ENTRY_DATA;
#define MAKE_CPU_REV_PCI_ENTRY(Family, Revision, Address, Data, Mask) MAKE_ENTRY_TYPE (CpuRevPciRegister), MAKE_CPU_LOGICAL_ID (Family, Revision), MAKE_PCI_DATA (Address, Data, Mask)

/**
 * Table Entry Data for CPU revision specific MSRs.
 *
 * Apply data to register after mask, for MSRs.
 */
typedef struct {
  CPU_LOGICAL_ID  CpuRevision;        ///< Common CPU Logical ID match criteria.
  UINT32          Address;            ///< MSR Address
  UINT64          Data;               ///< Data to be written into MSR
  UINT64          Mask;               ///< Mask to be used before data write. Set every bit of all updated fields.
} CPU_REV_MSR_TYPE_ENTRY_DATA;
#define MAKE_CPU_REV_MSR_ENTRY(Family, Revision, Address, Data, Mask) MAKE_ENTRY_TYPE (CpuRevMsr), MAKE_CPU_LOGICAL_ID (Family, Revision), MAKE_MSR_DATA (Address, Data, Mask)

/**
 * Table Entry Data for Family Specific Workarounds that depend on CPU revision.
 *
 * See if you can use the other entries or make an entry specifically for the fix.
 * After all, the purpose of having a table entry is to @b NOT have code which
 * isn't generic feature code, but is family/model specific.
 *
 * Call DoAction passing Data.
 */
typedef struct {
  CPU_LOGICAL_ID        CpuRevision;        ///< Common CPU Logical ID match criteria.
  UINT32                FunctionIndex;      ///< A function implementing the workaround.
  UINT32                Data;               ///< This data is passed to DoAction().
} CPU_REV_FAM_SPECIFIC_WORKAROUND_TYPE_ENTRY_DATA;
#define MAKE_CPU_REV_FAM_SPECIFIC_WORKAROUND_ENTRY(Family, Revision, FunctionIndex, Data) MAKE_ENTRY_TYPE (CpuRevFamSpecificWorkaround), MAKE_CPU_LOGICAL_ID (Family, Revision), MAKE_FAM_SPECIFIC_WORKAROUND_DATA (FunctionIndex, Data)

/**
 * Table Entry Data for SMU Index/Data D0F0xBC_xxxx_xxxx Registers.
 *
 * Apply data to register after mask, for PCI Config registers.
 */
typedef struct {
  UINT32    Index;                    ///< SMU index address
  UINT32    Data;                     ///< Data to be written into PCI device
  UINT32    Mask;                     ///< Mask to be used before data write. Set every bit of all updated fields.
} SMU_INDEX_ENTRY_DATA;
#define MAKE_SMU_INDEX_ENTRY_DATA(Index, Data, Mask) BSU32 (Index), BSU32 (Data), BSU32 (Mask)
#define MAKE_SMU_INDEX_ENTRY(Index, Data, Mask) MAKE_ENTRY_TYPE (SmuIndexReg), MAKE_SMU_INDEX_ENTRY_DATA(Index, Data, Mask)

#define SMU_INDEX_ADDRESS (MAKE_SBDFO (0, 0, 0, 0, 0xB8))


/**
 * Table Entry Data for Profile Fixup to SMU Index/Data D0F0xBC_xxxx_xxxx Registers.
 *
 * If TypeFeats matches current config, apply data to register after mask for SMU Index/Data D0F0xBC_xxxx_xxxx registers.
 */
typedef struct {
  PERFORMANCE_PROFILE_FEATS TypeFeats; ///< Profile Fixup Features.
  SMU_INDEX_ENTRY_DATA SmuIndexEntry;  ///< The SMU Index/Data D0F0xBC_xxxx_xxxx register entry data.
} PROFILE_FIXUP_SMU_INDEX_ENTRY_DATA;
#define MAKE_PROFILE_FIXUP_SMU_INDEX_ENTRY(TypeFeats, Index, Data, Mask) MAKE_ENTRY_TYPE (ProfileFixupSmuIndexReg), MAKE_PERFORMANCE_PROFILE_FEATS (TypeFeats), MAKE_SMU_INDEX_ENTRY_DATA (Index, Data, Mask)

/**
 * Bit field description
 *
 * Describe register type, address, MSB, LSB
 */
typedef struct {
  UINT16           RegType;            ///< Register type
  UINT32           Address;            ///< Address
  UINT8            MSB;                ///< Most Significant Bit
  UINT8            LSB;                ///< Least Significant Bit
} COPY_BIT_FIELD_DESCRIPTION;
#define MAKE_COPY_BIT_FIELD_DESCRIPTION(RegType, Address, Msb, Lsb) MAKE_ENTRY_TYPE (RegType), BSU32 (Address), BSU8 (Msb), BSU8 (Lsb)

/**
 * Table Entry Data for copying bitfield from register A to register B.
 *
 * Copy bitfield from register A to register B.
 */
typedef struct {
  COPY_BIT_FIELD_DESCRIPTION Destination; ///< Destination register descriptor
  COPY_BIT_FIELD_DESCRIPTION Source;      ///< Source register descriptor
} COPY_BIT_FIELD_ENTRY_DATA;
#define COPY_BIT_FIELD_DEST(RegType, Address, Msb, Lsb) MAKE_COPY_BIT_FIELD_DESCRIPTION (RegType, Address, Msb, Lsb)
#define COPY_BIT_FIELD_SOURCE(RegType, Address, Msb, Lsb) MAKE_COPY_BIT_FIELD_DESCRIPTION (RegType, Address, Msb, Lsb)
#define MAKE_COPY_BIT_FIELD_ENTRY(Dest, Src) MAKE_ENTRY_TYPE (CopyBitField), Dest, Src
/*------------------------------------------------------------------------------------------*/
/*
 * A complete register table and table entries.
 */
/*------------------------------------------------------------------------------------------*/

/**
 * Format of table entries :
 *
 *  UINT16          EntryType \
 *  VariableLength  EntryData / one entry
 *  UINT16          EntryType \
 *  VariableLength  EntryData / one entry
 *  ...                       \
 *  ...                       / more entries...
 */

/**
 * All the available entry data types.
 *
 * we use TABLE_ENTRY_DATA in copy bitfield entry
 *
 */
typedef union {
  MSR_TYPE_ENTRY_DATA                              MsrEntry;                ///< MSR entry.
  PCI_TYPE_ENTRY_DATA                              PciEntry;                ///< PCI entry.
  FAM_SPECIFIC_WORKAROUND_TYPE_ENTRY_DATA          FamSpecificEntry;        ///< Family Specific Workaround entry.
  PROFILE_FIXUP_TYPE_ENTRY_DATA                    FixupEntry;              ///< Profile Fixup entry.
  CORE_COUNTS_PCI_TYPE_ENTRY_DATA                  CoreCountEntry;          ///< Core count dependent settings.
  COMPUTE_UNIT_COUNTS_PCI_TYPE_ENTRY_DATA          CompUnitCountEntry;      ///< Compute unit count dependent entry.
  COMPUTE_UNIT_COUNTS_MSR_TYPE_ENTRY_DATA          CompUnitCountMsrEntry;   ///< Compute unit count dependent MSR entry.
  CPU_REV_PCI_TYPE_ENTRY_DATA                      CpuRevPciEntry;          ///< CPU revision PCI entry.
  CPU_REV_FAM_SPECIFIC_WORKAROUND_TYPE_ENTRY_DATA  CpuRevFamSpecificEntry;  ///< CPU revision Family Specific Workaround entry.
  SMU_INDEX_ENTRY_DATA                             SmuIndexEntry;           ///< SMU Index Data entry.
  PROFILE_FIXUP_SMU_INDEX_ENTRY_DATA               ProfileFixupSmuIndexEntry; ///< Performance Profile fixups to SMU index data registers entry.
  COPY_BIT_FIELD_ENTRY_DATA                        CopyBitFieldEntry;       ///< Copy bitfield entry.
} TABLE_ENTRY_DATA;

/**
 * Register Table Entry common fields.
 *
 * All the various types of register table entries are subclasses of this object.
 */
typedef struct {
  UINT16                 EntryType;                  ///< The type of table entry this is.
  TABLE_ENTRY_DATA       EntryData;                  ///< The pointer to the first entry.
} TABLE_ENTRY_FIELDS;

/**
 * An entire register table.
 */
typedef struct {
  UINT32               Selector;                     ///< For efficiency, these cores should process this table
  CONST UINT8*         Table;                        ///< The table entries.
} REGISTER_TABLE;

/**
 * An entire register table at given time point.
 */
typedef struct {
  REGISTER_TABLE_TIME_POINT TimePoint;               ///< Time point
  CONST REGISTER_TABLE* CONST * CONST TableList;     ///< The table list.
} REGISTER_TABLE_AT_GIVEN_TP;
/*------------------------------------------------------------------------------------------*/
/*
 * Describe implementers for table entries.
 */
/*------------------------------------------------------------------------------------------*/

/**
 * Implement the semantics of a Table Entry Type.
 *
 * @TableEntryTypeInstances.
 *
 * @param[in]       CurrentEntry        The type specific entry data to be implemented (that is written).
 * @param[in]       PlatformConfig      Config handle for platform specific information
 * @param[in]       StdHeader           Config params for library, services.
 */
typedef VOID F_DO_TABLE_ENTRY (
  IN       UINT8                 **CurrentEntry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );
/// Reference to a method
typedef F_DO_TABLE_ENTRY *PF_DO_TABLE_ENTRY;

/**
 * Describe the attributes of a Table Entry Type.
 */
typedef struct {
  UINT16                 EntryType;                  ///< The type of table entry this describes.
  PF_DO_TABLE_ENTRY      DoTableEntry;               ///< Provide all semantics associated with TABLE_ENTRY_DATA
} TABLE_ENTRY_TYPE_DESCRIPTOR;

/*------------------------------------------------------------------------------------------*/
/*
 * Table related function prototypes (many are instance of F_DO_TABLE_ENTRY method).
 */
/*------------------------------------------------------------------------------------------*/

/**
 * Get the next register table
 */
REGISTER_TABLE **GetNextRegisterTable (
  IN       UINT32                  Selector,
  IN       REGISTER_TABLE        **RegisterTableList,
  IN OUT   REGISTER_TABLE       ***RegisterTableHandle,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * If current core is CoreSelector core
 */
BOOLEAN
IsCoreSelector (
  IN       UINT32                    Selector,
  IN       AMD_CONFIG_PARAMS        *StdHeader
  );

/**
 * Set the registers for this core based on entries in a list of Register Table.
 */
VOID
SetRegistersFromTable (
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       UINT8                  *RegisterEntry,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Set the registers for this core based on entries in a list of Register Table.
 */
VOID
SetRegistersFromTableList (
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       REGISTER_TABLE         **RegisterTableList,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Processes the register table at the given time point.
 */
AGESA_STATUS
SetRegistersFromTablesAtGivenTimePoint (
  IN       VOID                      *PlatformConfig,
  IN       REGISTER_TABLE_TIME_POINT  TimePoint,
  IN       AMD_CONFIG_PARAMS         *StdHeader
  );

/**
 * Find the features of the running platform.
 */
VOID
GetPlatformFeatures (
     OUT   PLATFORM_FEATS    *Features,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS *StdHeader
  );

/**
 * Checks register table entry type specific criteria to the platform.
 */
BOOLEAN
DoesEntryTypeSpecificInfoMatch (
  IN       UINT32   PlatformTypeSpecificFeatures,
  IN       UINT32   EntryTypeFeatures
  );

/**
 * Perform the MSR Register Entry.
 */
VOID
SetRegisterForMsrEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the CPU Rev MSR Entry.
 */
VOID
SetRegisterForCpuRevMsrEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the PCI Register Entry.
 */
VOID
SetRegisterForPciEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the PCI Register Entry.
 */
VOID
SetRegisterForCpuRevPciEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Performance Profile PCI Register Entry.
 */
VOID
SetRegisterForPerformanceProfileEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Core Counts Performance PCI Register Entry.
 */
VOID
SetRegisterForCoreCountsPerformanceEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Compute Unit Counts PCI Register Entry.
 */
VOID
SetRegisterForComputeUnitCountsEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Compute Unit Counts MSR Register Entry.
 */
VOID
SetMsrForComputeUnitCountsEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Family Specific Workaround Register Entry.
 */
VOID
SetRegisterForFamSpecificWorkaroundEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Family Specific Workaround Register Entry.
 */
VOID
SetRegisterForCpuRevFamSpecificWorkaroundEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the SMU Index/Data Register Entry.
 */
VOID
SetSmuIndexRegisterEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Performance Profile SMU Index/Data Register Entry.
 */
VOID
SetSmuIndexRegisterForPerformanceEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Perform the Copy Bitfield Entry.
 */
VOID
CopyBitFieldEntry (
  IN       UINT8                 **Entry,
  IN       PLATFORM_CONFIGURATION *PlatformConfig,
  IN       AMD_CONFIG_PARAMS      *StdHeader
  );

/**
 * Compare counts to a pair of ranges.
 */
BOOLEAN
IsEitherCountInRange (
  IN       UINTN                FirstCount,
  IN       UINTN                SecondCount,
  IN       COUNT_RANGE_FEATURE  Ranges
  );

/**
 * Returns the performance profile features list of the currently running processor core.
 */
VOID
GetPerformanceFeatures (
     OUT   PERFORMANCE_PROFILE_FEATS    *Features,
  IN       PLATFORM_CONFIGURATION       *PlatformConfig,
  IN       AMD_CONFIG_PARAMS            *StdHeader
  );

#endif  // _CPU_TABLE_H_